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

У меня есть два шаблона данных в ресурсах и DataTemplateSelector, чтобы выбирать между ними:

    <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 или Name2) в привязке (вместо Name1OrName2, см. Выше). Спасибо.


person Jupirage    schedule 21.12.2016    source источник


Ответы (1)


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

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

Я нашел здесь вероятный обходной путь, но я не уверен, что рентабельность инвестиций будет хорошо складываться по сравнению с копированием. и вставляем 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 и _ 19_ являются два очень разных класса, которые делают разные вещи. Люди неправильно используют слово «привязка» для обозначения «поручения». Это не. Здесь вы вообще не используете никаких привязок.

person 15ee8f99-57ff-4f92-890c-b56153    schedule 21.12.2016
comment
Спасибо, Эдвард, за ответ. Я просто хочу прояснить вопрос привязки к полям Name1 и Name2 из DataGridTemplateColumn. - person Jupirage; 22.12.2016
comment
Извините, я неправильно понял ваши потребности. Это невозможно. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
В Интернете нашла разгадку. Внутри SelectTemplate, в момент, когда DataTemplate собирается вернуться, мы можем изменить привязки шаблона с помощью FrameworkElementFactory, чтобы назначить правильный путь: Name1 или Name2. Подобно factory.SetBinding (ContentPresenter.ContentProperty, new Binding (Path)); Я еще не совсем уверен. Что бы вы сказали? - person Jupirage; 22.12.2016
comment
@Jupirage Извините за этот комментарий, я пытался удалить его, но явно не сделал этого. MarkupExtension не является объектом зависимости, поэтому нет возможности использовать привязки к его свойствам, но, конечно, всегда может быть жизнеспособный обходной путь. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
@Jupirage Но вы говорите, что довольны своим селектором шаблонов, но что вы действительно хотите параметризовать, так это имя свойства, к которому привязаны шаблоны? (Я дал вам хороший ответ на совершенно не связанный с этим вопрос - ой!) - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
@Jupirage Обновленный ответ с моим лучшим текущим предположением о том, что вы пытаетесь сделать. Все еще не уверен. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
Фактически, каждая линия сетки представляет собой КРАСНЫЙ или ЗЕЛЕНЫЙ элемент. И есть ДВА похожих столбца, привязанных к строковым полям Name1 и Name2 каждой записи. Поскольку эти столбцы выглядят одинаково и различаются только путями привязки, я решил сделать их основанными на одной и той же паре шаблонов данных и одном селекторе. Итак, мне удалось параметризовать КРАСНЫЙ / ЗЕЛЕНЫЙ, но не Name1 / Name2. Фактически задача может быть поставлена ​​без Селектора. Только как использовать один DataTemplate с несколькими полями данных (столбцами сетки). - person Jupirage; 22.12.2016
comment
Сначала задача казалась мне довольно простой: нужно просто извлечь привязку из шаблона и изменить его Path. Тогда я понял, что это нетривиальная задача. И я сдался сейчас! Я просто скопировал / вставил два моих шаблона, изменил Путь и все. Теперь у меня 4 шаблона вместо 2. - person Jupirage; 22.12.2016
comment
Ой, хорошо, я, должно быть, был наполовину проснулся: у каждого RedItem и GreenItem есть Name1 и Name2, или что-то в этом роде? Я считаю, что лучше всего четыре шаблона. Если шаблоны достаточно сложны для обслуживания, вы можете создать шаблон в шаблоне - я добавляю это в обновлении. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
RedItem и GreenItem имеют Name1 и Name2 - это верно. Спасибо и прошу прощения за мою неясность. - person Jupirage; 22.12.2016
comment
@Jupirage Нет, совсем нет. Я поспешил с выводами вместо того, чтобы думать о том, что вы говорили. Мне настолько понравилась моя MarkupExtension идея, что я ушел писать код, прежде чем внимательно прочитал ваш вопрос. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
@Jupirage Я редактировал ваш заголовок, надеюсь, вы не против. - person 15ee8f99-57ff-4f92-890c-b56153; 22.12.2016
comment
Теперь название отличное! Я сохранил ваш код с помощью MarkupExtension, надеюсь однажды им воспользоваться. - person Jupirage; 22.12.2016