基于泛型类型的 WPF 数据模板选择器
WPF Data Template Selector based on Generic Types
我看过很多如何使用数据模板选择器根据 x:TargetType 显示不同控件的示例。我想根据 class 类型创建一个显示 RadioButton、TextBox 或 TextBlock 的项目控件。
我的 class 可能是这样的:
public class MyExample<T>
{
public string Name {get;set;}
public Type Type => TypeOf(T)
public T Value {get;set;}
}
我知道 Xaml 无法识别泛型,我不想创建支持泛型的标记扩展,我想保持简单。我不想为每种类型创建一个具体的 class。
我知道我可以使用数据触发器根据 属性(例如类型名称或类型类型)设置内容模板,但我认为使用数据模板选择器应该是一种更简单的方法。我可以在类型 属性 上使用 TargetType 而不是 class 类型吗?
Can I use the TargetType on the Type Property instead of class type?
没有
显而易见的解决方案是为 T
的每种类型创建一个子类型和相应的 DataTemplate
。每个子类型的实现都是一行:
public class MyExampleInt : MyExample<int> { }
public class MyExampleString : MyExample<string> { }
如果您出于某种原因不想创建具体的子类型,您可以使用 DataTemplateSelector
到 select 基于每个 MyExample<T>
类型的模板:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
switch (item)
{
case MyExample<int> i:
return IntTemplate;
case MyExample<string> s:
return StringTemplate;
}
return null;
}
这对我有用:
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:local="clr-namespace:WpfApp1" xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
mc:Ignorable="d"
Background="Red"
d:DataContext="{d:DesignInstance local:ViewModel}"
WindowStartupLocation="CenterScreen"
Title="MainWindow" d:Height="100" d:Width="150" Width="300" Height="300">
<Window.Resources>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Center"/>
</Style>
<DataTemplate x:Key="DefaultTemplate">
<TextBlock Text="{Binding Value}" Style="{StaticResource TextBlockStyle}"/>
</DataTemplate>
<DataTemplate x:Key="NumberTemplate">
<syncfusion:UpDown Name="NumericUpdDown" Value="{Binding Value}"/>
</DataTemplate>
<DataTemplate x:Key="TextTemplate">
<TextBlock Text="{Binding Value}" Style="{StaticResource TextBlockStyle}" />
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox IsChecked="{Binding Value}" HorizontalAlignment="Center"/>
</DataTemplate>
<DataTemplate x:Key="MyDataTemplate">
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<!-- Default Template -->
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<!-- Triggers to change Template -->
<Style.Triggers>
<DataTrigger Binding="{Binding Type.Name}" Value="Int32">
<Setter Property="ContentTemplate" Value="{StaticResource NumberTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type.Name}" Value="String">
<Setter Property="ContentTemplate" Value="{StaticResource TextTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type.Name}" Value="Boolean">
<Setter Property="ContentTemplate" Value="{StaticResource CheckBoxTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</Window.Resources>
<ItemsControl
ItemsSource="{Binding Definitions}"
ItemTemplate="{StaticResource MyDataTemplate}">
</ItemsControl>
</Window>
我不想要具体类型的原因 class 是为了避免每次添加新类型时添加大量代码。您如何看待这个解决方案?
我看过很多如何使用数据模板选择器根据 x:TargetType 显示不同控件的示例。我想根据 class 类型创建一个显示 RadioButton、TextBox 或 TextBlock 的项目控件。 我的 class 可能是这样的:
public class MyExample<T>
{
public string Name {get;set;}
public Type Type => TypeOf(T)
public T Value {get;set;}
}
我知道 Xaml 无法识别泛型,我不想创建支持泛型的标记扩展,我想保持简单。我不想为每种类型创建一个具体的 class。 我知道我可以使用数据触发器根据 属性(例如类型名称或类型类型)设置内容模板,但我认为使用数据模板选择器应该是一种更简单的方法。我可以在类型 属性 上使用 TargetType 而不是 class 类型吗?
Can I use the TargetType on the Type Property instead of class type?
没有
显而易见的解决方案是为 T
的每种类型创建一个子类型和相应的 DataTemplate
。每个子类型的实现都是一行:
public class MyExampleInt : MyExample<int> { }
public class MyExampleString : MyExample<string> { }
如果您出于某种原因不想创建具体的子类型,您可以使用 DataTemplateSelector
到 select 基于每个 MyExample<T>
类型的模板:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
switch (item)
{
case MyExample<int> i:
return IntTemplate;
case MyExample<string> s:
return StringTemplate;
}
return null;
}
这对我有用:
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:local="clr-namespace:WpfApp1" xmlns:syncfusion="http://schemas.syncfusion.com/wpf"
mc:Ignorable="d"
Background="Red"
d:DataContext="{d:DesignInstance local:ViewModel}"
WindowStartupLocation="CenterScreen"
Title="MainWindow" d:Height="100" d:Width="150" Width="300" Height="300">
<Window.Resources>
<Style x:Key="TextBlockStyle" TargetType="TextBlock">
<Setter Property="TextAlignment" Value="Center"/>
</Style>
<DataTemplate x:Key="DefaultTemplate">
<TextBlock Text="{Binding Value}" Style="{StaticResource TextBlockStyle}"/>
</DataTemplate>
<DataTemplate x:Key="NumberTemplate">
<syncfusion:UpDown Name="NumericUpdDown" Value="{Binding Value}"/>
</DataTemplate>
<DataTemplate x:Key="TextTemplate">
<TextBlock Text="{Binding Value}" Style="{StaticResource TextBlockStyle}" />
</DataTemplate>
<DataTemplate x:Key="CheckBoxTemplate">
<CheckBox IsChecked="{Binding Value}" HorizontalAlignment="Center"/>
</DataTemplate>
<DataTemplate x:Key="MyDataTemplate">
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<!-- Default Template -->
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}" />
<!-- Triggers to change Template -->
<Style.Triggers>
<DataTrigger Binding="{Binding Type.Name}" Value="Int32">
<Setter Property="ContentTemplate" Value="{StaticResource NumberTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type.Name}" Value="String">
<Setter Property="ContentTemplate" Value="{StaticResource TextTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Type.Name}" Value="Boolean">
<Setter Property="ContentTemplate" Value="{StaticResource CheckBoxTemplate}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</Window.Resources>
<ItemsControl
ItemsSource="{Binding Definitions}"
ItemTemplate="{StaticResource MyDataTemplate}">
</ItemsControl>
</Window>
我不想要具体类型的原因 class 是为了避免每次添加新类型时添加大量代码。您如何看待这个解决方案?