代码之家  ›  专栏  ›  技术社区  ›  Martin Hennings

如何在datatemplate的datatype属性中引用泛型类型的特定实现?

  •  0
  • Martin Hennings  · 技术社区  · 14 年前

    这个问题与这个答案紧密相连 How to reference a generic type in the DataType attribute of a 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有自己的datatemplate视图。
    所以现在我有了staticresource“dictemvmofstringtoremoteaddress”,我想用它来指定一个数据模板:

    <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>
    

    现在这个数据模板 应该 用作视图,但显示的是basevm的视图。
    有人给我一个暗示吗?

    [编辑:2010-08-09]
    我试过的一些事情:

    在x:数组定义中,我替换了
    <mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/>
    具有
    <x:Type TypeName="remote:Address"/> ,
    因为基本上就是这样-没有区别。

    还尝试在标记之间创建数据类型(而不是链接到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>
    

    在genericType.innertypes中尝试使用或不使用x:array,这两种方法都给了我 this 错误。

    试图从如下静态属性传递类型:
    DataType="{x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}"
    像这样:
    DataType="{Binding Path={x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}}"
    没有区别。

    很奇怪,这个特定的数据模板需要 x:Key 值,与XAML资源文件中所有其他指向常规类型的值不同,例如: DataType="{x:Type mvvm:EffectVM}" . 如果我取下x:键,我会 this 错误。

    1 回复  |  直到 14 年前
        1
  •  1
  •   Martin Hennings    14 年前

    我找到了一个解决方案,尽管这个解决方案并不真正令人满意。

    在XAML中,为每种类型的 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中没有复杂的嵌套类型描述,因为上面的解决方案需要这样做。
    推荐文章