我可以在 XAML (在.NET4Framework 之前)中指定一个泛型类型吗?

在 XAML 中,我可以声明一个 DataTemplate,以便在显示特定类型时使用该模板。例如,此 DataTemplate 将使用 TextBlock 来显示客户的名称:

<DataTemplate DataType="{x:Type my:Customer}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>

我想知道是否可以定义一个 DataTemplate,它将在任何时候显示 IList < Customer > 时使用。因此,如果 ContentControl 的 Content 是,比方说,一个 Observer ableCollection < Customer > ,它将使用该模板。

是否可以使用{ x: Type }标记扩展在 XAML 中声明类似 IList 的泛型类型?

43062 次浏览

虽然没有开箱即用,但是已经有一些有进取心的开发人员这样做了。

例如,微软的迈克 · 希尔伯格(MikeHillberg)在 这篇文章中使用了它,当然谷歌也有其他的。

不能直接在 XAML 中使用,但是您可以从 XAML 中引用 DataTemplateSelector来选择正确的模板。

public class CustomerTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
DataTemplate template = null;
if (item != null)
{
FrameworkElement element = container as FrameworkElement;
if (element != null)
{
string templateName = item is ObservableCollection<MyCustomer> ?
"MyCustomerTemplate" : "YourCustomerTemplate";


template = element.FindResource(templateName) as DataTemplate;
}
}
return template;
}
}


public class MyCustomer
{
public string CustomerName { get; set; }
}


public class YourCustomer
{
public string CustomerName { get; set; }
}

资源词典:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
>
<DataTemplate x:Key="MyCustomerTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<TextBlock Text="My Customer Template"/>
<ListBox ItemsSource="{Binding}"
DisplayMemberPath="CustomerName"
Grid.Row="1"/>
</Grid>
</DataTemplate>


<DataTemplate x:Key="YourCustomerTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<TextBlock Text="Your Customer Template"/>
<ListBox ItemsSource="{Binding}"
DisplayMemberPath="CustomerName"
Grid.Row="1"/>
</Grid>
</DataTemplate>
</ResourceDictionary>

窗口 XAML:

<Window
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
xmlns:local="clr-namespace:WpfApplication1"
>
<Grid>
<Grid.Resources>
<local:CustomerTemplateSelector x:Key="templateSelector"/>
</Grid.Resources>
<ContentControl
Content="{Binding}"
ContentTemplateSelector="{StaticResource templateSelector}"
/>
</Grid>
</Window>

背后的窗口代码:

public partial class Window1
{
public Window1()
{
InitializeComponent();
ObservableCollection<MyCustomer> myCustomers
= new ObservableCollection<MyCustomer>()
{
new MyCustomer(){CustomerName="Paul"},
new MyCustomer(){CustomerName="John"},
new MyCustomer(){CustomerName="Mary"}
};


ObservableCollection<YourCustomer> yourCustomers
= new ObservableCollection<YourCustomer>()
{
new YourCustomer(){CustomerName="Peter"},
new YourCustomer(){CustomerName="Chris"},
new YourCustomer(){CustomerName="Jan"}
};
//DataContext = myCustomers;
DataContext = yourCustomers;
}
}

Aelij (WPF 捐款项目的项目协调员)有另一个 方式来做这件事。

更酷的是(即使它在未来的某个时候是关闭的) ... ... XAML 2009(XAML 2006是当前版本)将本地支持这一点。看看这个 PDC 2008年会议的信息,它和更多。

还可以将泛型类包装在指定 T 的派生类中

public class StringList : List<String>{}

并使用 XAML 中的 StringList。

这完全违背了泛型的目的,但是您可以定义一个从这样的泛型派生的类,其唯一的目的是能够在 XAML 中使用该类型。

public class MyType : List<int> { }

在 xaml 中使用,例如

<DataTemplate DataType={x:Type myNamespace:MyType}>