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

发布于 2024-09-13 18:06:16 字数 3586 浏览 9 评论 0原文

这个问题与“如何在 HierarchicalDataTemplate 的 DataType 属性中引用泛型类型?

我遵循了该答案的基本思想并创建了此数据结构:

<!-- 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"/>

DictItemVMKeyValuePair<...> 的视图模型,派生自 BaseVM。 BaseVM 有一个 DataTemplate 视图,但我正在努力为 DictItemVM 创建一个视图。
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 定义中


,
因为这就是它的本质——没有区别。

还尝试在标签之间创建 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>

在 GenericType.InnerTypes 中尝试使用和不使用 x:Array ,两者都给了我 这个错误。

尝试从静态属性传递类型,如下所示:
DataType="{x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}"
像这样:
DataType="{绑定路径={x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}}"
没有区别。

奇怪的是,这个特定的 DataTemplate 需要有一些 x:Key 值,与 xaml 资源文件中的所有其他值相反,这些值都指向常规类型,例如: DataType="{x:输入 mvvm:EffectVM}"。如果我删除 x:Key,则会收到错误。

This question is strongly connected to this answer to "How to reference a generic type in the DataType attribute of a HierarchicalDataTemplate?"

I followed the basic idea of that answer and created this data structure:

<!-- 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> is a viewmodel for a KeyValuePair<...> and is derived from BaseVM. BaseVM has a DataTemplate view, but I'm trying hard to create one for DictItemVM<string, Remote.Address>.
Remote.Address is a complex value type (stores Path and Access information). Remote.Address has its own DataTemplate view.
So now that I have the StaticResource "DictItemVMOfStringToRemoteAddress", I want to use it to specify a 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>

Now this DataTemplate should be used as a view, but instead the view for BaseVM is being displayed.
Someone give me a hint on this one?

[edit: 2010-08-09]
Some things I tried:

In the x:Array definition I replaced
<mvvm:GenericType BaseType="{x:Type TypeName=remote:Address}"/>
with
<x:Type TypeName="remote:Address"/>,
because that's what it basically is - no difference.

Also tried to create the DataType in between tags (instead of linking to a StaticResource) like this:

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

Tried it with and without an x:Array within the GenericType.InnerTypes, both giving me this error.

Tried to pass the type from a static property like this:
DataType="{x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}"
and like this:
DataType="{Binding Path={x:Static mvvm:StaticTypes.DictItemVMOfStringToRemoteAddress}}"
No difference.

Strange enough this specific DataTemplate needs to have some x:Key value, in contrast to all others in the xaml resource file which all point to a regular type like e.g.: DataType="{x:Type mvvm:EffectVM}". If I remove the x:Key, I get this error.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赢得她心 2024-09-20 18:06:16

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

在 XAML 中,为要显示的每种类型的 KeyValuePair 创建一个 DataTemplate,并为其提供一些唯一的 x:Key:

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

然后在代码隐藏中,创建一个 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}"

--

缺点:

  • 创建新的 DataTemplate 时,必须在两个位置更改代码。
  • 每个 ContentControl、ListView...都必须设置其适当的属性。
  • 并没有真正回答如何在 WPF 中引用泛型类型的问题!

优点:

  • 易于添加任何结构或复杂性的新类型(享受 C# 相对于 WPF 的所有优点...)
  • 不复杂WPF 中的嵌套类型描述,如上述解决方案所需要的。

I found a solution, though that solution is not really satisfying.

In XAML, create a DataTemplate for each type of KeyValuePair<T,U> you want to display and give it some unique x:Key:

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

Then in codebehind, create a DataTemplateSelector and override 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;
    }
}

Again in XAML, declare this class as a resource:

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

Finally, (in my case) in the ContentControl, add the property:

ContentTemplateSelector="{StaticResource GenDataTempSelect}"

--

Disadvantages:

  • When creating a new DataTemplate you have to change code at two locations.
  • Each ContentControl, ListView, ... must set it's appropriate property.
  • Doesn't really answer the question of how to reference generic types in WPF!

Advantages:

  • Easy to add new types of any structure or complexity (enjoying all the benefits C# has over WPF...)
  • No complicated nested type description in WPF, as the above solution would require.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文