【发布时间】:2019-06-03 04:53:52
【问题描述】:
我已经阅读了近千篇文章,解释在 DataTemplate 上将封闭的泛型类型设置为 DataType 不起作用,因为 WPF 不支持。但事实上,这是错误的。
我可以在我的Window.Resources 中定义以下DataTemplate,当我将字符串列表分配给内容控件时将使用它。例如:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DataTemplate DataType="{x:Type TypeName=Generic:List`1[System.String]}">
<TextBlock Text="Hi List of Strings"
FontSize="40"
Foreground="Cyan"/>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl x:Name="_contentControl">
</ContentControl>
</Grid>
</Window>
在代码隐藏中:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
_contentControl.Content = new List<string> { "Huhu" };
}
}
通过此设置,您将看到“Hi List of Strings”。对我来说,这证明了我可以将泛型类型定义为DataType。但我想更进一步:我想将Dictionary<string, string> 定义为DataType。但不幸的是,我无法让它工作。
所以问题是:如何将Dictionary<string, string> 定义为DataTemplate 的DataType?
如果你知道答案,你可以停止阅读。但由于展示我已经做过的事情是一种很好的做法,所以我一直在写。 我已经做了什么? 起初我蛮力尝试了几种类似的组合:
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String];[System.String]}"
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String],[System.String]}"
- DataType="{x:Type TypeName=Generic:Dictionary`2[System.String,System.String]}"
但由于它们都不起作用,我深入到System.Xaml 并查看了TypeExtension、GenericTypeNameParser 和GenericTypeNameScanner,因为我认为这些是解析类型的代码行。但是查看代码我意识到 ` 是一个无效字符。
为了证明这一点,我写了自己的MarkupExtension
public class UseTheTypeExtensionsParser : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
var a = new TypeExtension("Generic:List`1[[System.String]]");
var type = a.ProvideValue(serviceProvider);
return type.ToString();
}
}
并按如下方式使用:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Generic="clr-namespace:System.Collections.Generic;assembly=mscorlib"
xmlns:WpfApp1="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ContentControl Content="{WpfApp1:UseTheTypeExtensionsParser}"/>
</Grid>
</Window>
这引发了异常,即字符 ` 不是预期的并且 XAML 类型无效。
这让我想知道为什么我的第一个示例有效。我认为,在为 WPF 标记编译 XAML 时,不是用于解析 XamlType 的 TypeExtension,但我认为使用了 XamlNamespace。因为这个类有MangleGenericTypeName-方法,它使用了`-字符。
但是我仍然看不到提取类型参数的代码,所以我看不到为字典指定类型参数的正确语法。这就是我卡住的地方。
(不用说微软文档在这个话题上毫无价值。)
编辑:由于似乎不清楚我为什么想要这个,我会解释一下:我想要自动选择ContentTemplate 的ContentControl。当然:我在示例中构造的DataTemplate 非常简单。但是每个人都应该能够想象到,我想要不同的 DataTemplates 用于 Lists、Dictionaries 或简单的字符串。
我有一个 ViewModel,它有一个 public object Result { get; } 属性。有时,结果是一个 int,有时是一个字符串,有时是一个 List 等等。我将此Result-property 绑定到ContentControl 的Content-Property。对于提到的所有类型,我编写了 WPF 自动选择的不同 DataTemplates。所以ints 显示在Rectangle 中,Strings 显示在Ellipse 中。
在我完成所有这些工作后,我想要另一个DataTemplate,但这次是Dictionary。
【问题讨论】:
-
这里没有任何泛型类型。你有一个 concrete 类型,
List<string>。泛型类型是List<T>。您不能仅仅因为 编译器 无法知道这些泛型类型中包含什么而使用泛型类型 -
不,MS 文档并非一文不值,也不是所有的人都说你不能错误地使用泛型类型。毕竟 WPF 是在 10 年前问世的,有人会注意到的。 几乎所有教程和文档都显示绑定到泛型类型,无论是
List<SomeEntity>或ObservableCollection<SomeOtherEntity>还是 EF 返回的内容 -
没关系,问题应该按原样关闭,我没有投反对票。为什么你认为你需要指定这样的类型?您要解决的实际问题是什么?数据模板通常用于在容器中显示 items,这就是为什么您会将字符串视为 DataType 而不是 IEnumerable
。容器由派生自 ItemsControls 的控件呈现,这些控件已经知道 IEnumerable -
最后,您甚至不需要在 DataTemplate 中指定
DataType。 WPF 数据绑定与反射一起使用,因此您无需指定类型,只要模板绑定到的对象具有满足绑定表达式的属性。 -
@Clemens 并且仍然需要 ItemsControl 来显示项目。即使需要一些转换,converter 也可以完成这项工作。无需创建标记扩展
标签: .net wpf xaml .net-4.6.2