【问题标题】:Can I specify a generic type in XAML (pre .NET 4 Framework)?我可以在 XAML(.NET 4 之前)中指定泛型类型吗?
【发布时间】:2010-09-16 04:01:28
【问题描述】:

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

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

我想知道是否可以定义一个在显示 IList 时将使用的 DataTemplate。因此,如果 ContentControl 的内容是 ObservableCollection,它将使用该模板。

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

【问题讨论】:

标签: c# wpf xaml generics


【解决方案1】:

不是直接在 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;
    }
}

【讨论】:

  • 可能是一个更好更简单的解决方案
  • 我发现这比其他模板选择器教程更容易理解。谢谢
【解决方案2】:

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

例如,微软的 Mike Hillberg 在this post 中使用过它。 Google 当然还有其他的。

【讨论】:

    【解决方案3】:

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

    public class StringList : List<String>{}
    

    并使用 XAML 中的 StringList。

    【讨论】:

    • 这对我有用。有一个完全空的类有点奇怪,但它完成了工作。
    • 我在stackoverflow.com/a/33827448/11635 中使用这种技术构建了一个通用包装器
    【解决方案4】:

    aelij(WPF Contrib 项目的项目协调员)有另一个 way 来做。

    更酷的是(即使它在未来的某个时候关闭)...... XAML 2009(XAML 2006 是当前版本)将在本机上支持这一点。查看PDC 2008 session 了解更多信息。

    【讨论】:

    • XAML 2009 仅在松散的 xaml 文件中受支持(从 .NET 4.0、WPF 4.0 开始)。也就是说,Blend、Cider(Visual Studio 设计器)和已编译的 BAML(这是您的嵌入式 xaml 编译成的内容)......不支持新语法。希望这将在 WPF 的未来版本中改变。查看以下链接并投票:dotnet.uservoice.com/forums/40583-wpf-feature-suggestions/…
    【解决方案5】:

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

    public class MyType : List<int> { }
    

    并在 xaml 中使用它,例如喜欢

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

    【讨论】:

      猜你喜欢
      • 2011-12-11
      • 2010-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多