2016-12-21 5 views
1

У меня есть два шаблона данных в ресурсах и DataTemplateSelector выбирать между ними:Используя тот же DataTemplate для двух разных свойств одного и того же объекта в двух DataGridTemplateColumns

<DataGrid.Resources> 
     <DataTemplate x:Key="RedTemplate"> 
      <TextBlock Text="{Binding **Name1OrName2**}" />       
     </DataTemplate > 

     <DataTemplate x:Key="GreenTemplate"> 
     ....     
     </DataTemplate> 

     <local:MyTemplateSelector x:Key="MyTemplateSelector" 
       RedTemplate="{StaticResource RedTemplate}" 
       GreenTemplate="{StaticResource GreenTemplate}" /> 

    </DataGrid.Resources> 

Вот код-позади селектор:

public class MyTemplateSelector : DataTemplateSelector 
    { 
     public DataTemplate RedTemplate { get; set; } 
     public DataTemplate GreenTemplate { get; set; } 

     public override DataTemplate SelectTemplate(object item, DependencyObject container) 
     { 
      if (item is RedItem) return RedTemplate; 
      else if (item is GreenItem) return GreenTemplate; 
      else return base.SelectTemplate(item, container);      
     } 
    } 

пока я использую MyTemplateSelector для одного DataColumn (скажем, name1), он отлично работает. Но мой DataGrid имеет две колонки шаблон быть связан с двумя строковыми полями: NAME1 и NAME2

<DataGridTemplateColumn CellTemplateSelector="{StaticResource MyTemplateSelector}" > // Should be bound to Name1  
<DataGridTemplateColumn CellTemplateSelector="{StaticResource MyTemplateSelector}" > // Should be bound to Name2 

Мой вопрос: как я могу установить правильный путь (Name1 или Имя2) в связывании (вместо Name1OrName2 см выше). Спасибо.

ответ

2

Похоже, что мой первоначальный ответ был вызван неправильным пониманием вопроса, и требование заключается не в селекторе шаблонов данных, а в том, как параметризовать свойство, к которому привязывается привязка, поэтому вы можете использовать тот же шаблон для двух разных свойств.

Быстрый ответ: Это не тот способ, которым XAML предназначен для использования. Вы не можете параметризовать свойство Path объекта Binding. Обычным решением является написать один шаблон для каждого случая. Было бы неплохо, если бы вы могли указать, какое свойство/поле должно отображать DataGridTemplateColumn, через свойство или DisplayMemberPath, а затем передать это значение шаблону - но это не работает.

I found a likely-looking workaround here, но я не уверен, что ROI на нем будет складываться хорошо относительно копирования и вставки DataTemplate и продолжения вашей жизни.

Если шаблоны достаточно сложна для обслуживания, чтобы быть беспокойство, вы можете работать вокруг, что вот так:

XAML ресурсов:

<DataTemplate x:Key="RedBaseTemplate"> 
    <Border BorderBrush="Green" BorderThickness="2" Margin="1"> 
     <Label x:Name="Text" Background="Red" Content="{Binding}" /> 
    </Border> 
</DataTemplate> 
<DataTemplate x:Key="GreenBaseTemplate"> 
    <Border BorderBrush="Red" BorderThickness="2" Margin="1"> 
     <Label x:Name="Text" Background="Green" Content="{Binding}" /> 
    </Border> 
</DataTemplate> 

<DataTemplate x:Key="RedTemplateA"> 
    <ContentControl 
     Content="{Binding A}" 
     ContentTemplate="{StaticResource RedBaseTemplate}" 
     /> 
</DataTemplate> 
<DataTemplate x:Key="RedTemplateB"> 
    <ContentControl 
     Content="{Binding B}" 
     ContentTemplate="{StaticResource RedBaseTemplate}" 
     /> 
</DataTemplate> 
<DataTemplate x:Key="GreenTemplateA"> 
    <ContentControl 
     Content="{Binding A}" 
     ContentTemplate="{StaticResource GreenBaseTemplate}" 
     /> 
</DataTemplate> 
<DataTemplate x:Key="GreenTemplateB"> 
    <ContentControl 
     Content="{Binding B}" 
     ContentTemplate="{StaticResource GreenBaseTemplate}" 
     /> 
</DataTemplate> 

оригинальный ответ

Это общий шаблон: вы хотите, чтобы несколько экземпляров одного и того же DataTemplateSelector (или конвертер значений, довольно часто), но с разными параметрами. Решение состоит в том, чтобы получить от MarkupExtension, поэтому вы можете создать экземпляр объекта в точке использования с его собственными уникальными параметрами, а не создавать один общий экземпляр где-то еще в качестве ресурса. В этом случае DataTemplateSelector - это класс, а не интерфейс, поэтому вы не можете получить свой селектор от MarkupExtension. Вместо этого вы пишете быстрый MarkupExtension, который возвращает ваш селектор.

Я хотел сам пройти шаблоны до RedGreenTemplateSelectorExtension, используя StaticResource или DynamicResource в XAML, но синтаксическому анализатору XAML не понравилась эта идея. Но это работает достаточно хорошо.

public class RedGreenTemplateSelectorExtension : MarkupExtension 
{ 
    public Object RedTemplateKey { get; set; } 
    public Object GreenTemplateKey { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     var redTemplate = new StaticResourceExtension(RedTemplateKey) 
      .ProvideValue(serviceProvider) as DataTemplate; 

     var greenTemplate = new StaticResourceExtension(GreenTemplateKey) 
      .ProvideValue(serviceProvider) as DataTemplate; 

     return new RedGreenTemplateSelector() { 
      RedTemplate = redTemplate, 
      GreenTemplate = greenTemplate 
     }; 
    } 
} 

public class RedGreenTemplateSelector : DataTemplateSelector 
{ 
    public DataTemplate RedTemplate { get; set; } 
    public DataTemplate GreenTemplate { get; set; } 

    public override DataTemplate SelectTemplate(object item, DependencyObject container) 
    { 
     if (item is RedItem) 
      return RedTemplate; 
     else if (item is GreenItem) 
      return GreenTemplate; 
     else 
      return base.SelectTemplate(item, container); 
    } 
} 

XAML

<StackPanel> 
    <ContentControl 
     ContentTemplateSelector="{local:RedGreenTemplateSelector RedTemplateKey=RedTemplate, GreenTemplateKey=GreenTemplate}" 
     > 
     <local:RedItem/> 
    </ContentControl> 
    <ContentControl 
     ContentTemplateSelector="{local:RedGreenTemplateSelector RedTemplateKey=RedTemplate, GreenTemplateKey=GreenTemplate}" 
     > 
     <local:GreenItem/> 
    </ContentControl> 
</StackPanel> 

P.S. StaticResource и Binding - это два совершенно разных класса, которые делают разные вещи. Люди злоупотребляют «привязкой» к «присвоению». Это не. Здесь вы не используете никаких привязок.

+0

Спасибо, Эдвард за ваш ответ. Я просто хотел бы прояснить вопрос привязки к полям Name1 и Name2 из DataGridTemplateColumn. – Jupirage

+0

Прошу прощения, я неправильно понял ваши потребности. Это невозможно. –

+0

В Интернете я нашел ключ. Внутри SelectTemplate, в тот момент, когда DataTemplate собирается вернуться, мы можем изменить привязки шаблона с помощью FrameworkElementFactory, чтобы назначить правильный Путь: «Name1» или «Name2». Как factory.SetBinding (ContentPresenter.ContentProperty, новое связывание (путь)); Я еще не совсем уверен. Что бы вы сказали? – Jupirage