Как сослаться на конкретную реализацию универсального типа в атрибуте DataType DataTemplate? - PullRequest
0 голосов
/ 05 августа 2010

Этот вопрос тесно связан с этим ответом на вопрос " Как ссылаться на универсальный тип в атрибуте DataType HierarchicalDataTemplate? "

Я следовал основной идее этого ответа и создал эту структуру данных:

<!-- for DictItemVM<string, Remote.Address> which is a viewmodel for a KeyValuePair<...> -->
<x:Array Type="{x:Type sys:Type}"
         x:Key="KVParamsStringToRemoteAddress"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:sys="clr-namespace:System;assembly=mscorlib"
         xmlns:remote="clr-namespace:Remote"
         xmlns:mvvm="clr-namespace:MVVM">
    <x:Type TypeName="sys:String" />
    <mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/>
</x:Array>

<mvvm:GenericType xmlns:mvvm="clr-namespace:MVVM"
                  BaseType="{x:Type TypeName=mvvm:DictItemVM`2}"
                  InnerTypes="{StaticResource KVParamsStringToRemoteAddress}"
                  x:Key="DictItemVMOfStringToRemoteAddress"/>

DictItemVM<T,U> является моделью представления для KeyValuePair<...> и является производной от BaseVM. BaseVM имеет представление DataTemplate, но я очень стараюсь создать его для DictItemVM<string, Remote.Address>.
Remote.Address - сложный тип значения (хранит информацию о путях и доступе). Remote.Address имеет собственное представление DataTemplate.
Итак, теперь, когда у меня есть StaticResource "DictItemVMOfStringToRemoteAddress", я хочу использовать его для указания DataTemplate:

<DataTemplate x:Key="TestKey" DataType="{StaticResource DictItemVMOfStringToRemoteAddress}">
    <StackPanel>
        <Label Content="UniqueName" />
        <TextBox Text="{Binding UniqueName}" />
        <Label Content="Key"/>
        <TextBox Text="{Binding Key, Mode=OneWay}" IsEnabled="False" />
        <Label Content="Value"/>
        <ContentControl Content="{Binding Value, Mode=OneWay}" />
    </StackPanel>
</DataTemplate>

Теперь этот DataTemplate следует использовать в качестве представления, но вместо этого отображается представление для BaseVM.
Кто-нибудь подскажет мне об этом?

[редактировать: 2010-08-09]
Некоторые вещи, которые я пробовал:

В определении x: Array я заменил
<mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/>
с
<x:Type TypeName="remote:Address"/>
потому что это то, что это в принципе - без разницы.

Также пытался создать DataType между тегами (вместо ссылки на StaticResource) следующим образом:

<DataTemplate x:Key="TestKey">
    <DataTemplate.DataType>
        <Binding>
            <Binding.Source>
                <mvvm:GenericType 
                  BaseType="{x:Type TypeName=mvvm:DictItemVM`2}">
                    <mvvm:GenericType.InnerTypes>
                        <x:Type TypeName="sys:String" />
                        <x:Type TypeName="remote:Address"/>
                    </mvvm:GenericType.InnerTypes>
                </mvvm:GenericType>
            </Binding.Source>
        </Binding>
    </DataTemplate.DataType>

Пробовал с и без x: Array в GenericType.InnerTypes, оба дают мне эту ошибку.

Пытался передать тип из статического свойства следующим образом:
DataType="{x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}"
и вот так:
DataType="{Binding Path={x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}}"
Без разницы.

Достаточно странно, что этот конкретный DataTemplate должен иметь некоторое значение x:Key, в отличие от всех других в файле ресурсов xaml, которые все указывают на обычный тип, например, DataType="{x:Type mvvm:EffectVM}". Если я удалю ключ x:, я получу эту ошибку.

1 Ответ

1 голос
/ 11 августа 2010

Я нашел решение, хотя это решение на самом деле не удовлетворяет.

В XAML создайте DataTemplate для каждого типа KeyValuePair<T,U>, который вы хотите отобразить, и дайте ему какой-то уникальный x: Key:

<DataTemplate x:Key="DictItemOfStringAndAddressVM">
    <!-- ... -->
</DataTemplate>

Затем в codebehind создайте DataTemplateSelector и переопределите SelectTemplate:

public class GenericDataTemplateSelector : System.Windows.Controls.DataTemplateSelector
{
    public override System.Windows.DataTemplate SelectTemplate(object item, System.Windows.DependencyObject container)
    {
        FrameworkElement element = container as FrameworkElement;

        if ((element != null) && (item != null))
        {
            if (item is DictItemVM<string, Remote.Address>)
            {
                return element.FindResource("DictItemOfStringAndAddressVM") as DataTemplate;
            }
            else if(item is SomeOtherComplexType)
            {
                // ...
            }
            else return base.SelectTemplate(item, container);
        }
        return null;
    }
}

Снова в XAML объявите этот класс как ресурс:

<mvvm:GenericDataTemplateSelector x:Key="GenDataTempSelect"/>

Наконец, (в моем случае) в ContentControl добавьте свойство:

ContentTemplateSelector="{StaticResource GenDataTempSelect}"

-

Недостатки:

  • При создании нового шаблона данных необходимо изменить кодв двух местах.
  • Каждый ContentControl, ListView, ... должен установить соответствующее свойство.
  • Не совсем отвечает на вопрос, как ссылаться на универсальные типы в WPF!

Преимущества:

  • Легко добавлять новые типы любой структуры или сложности (наслаждаясь всеми преимуществами C # по сравнению с WPF ...)
  • Нет сложного описания вложенного типа в WPF, так как вышеприведенное решение будетТребуется.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...