C# 我可以在 XAML(.NET 4 Framework 之前)中指定泛型类型吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/185349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:03:45  来源:igfitidea点击:

Can I specify a generic type in XAML (pre .NET 4 Framework)?

c#wpfxamlgenerics

提问by Matt Hamilton

In XAML I can declare a DataTemplate so that the template is used whenever a specific type is displayed. For example, this DataTemplate will use a TextBlock to display the name of a customer:

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

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

I'm wondering if it's possible to define a DataTemplate that will be used any time an IList<Customer> is displayed. So if a ContentControl's Content is, say, an ObservableCollection<Customer> it would use that template.

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

Is it possible to declare a generic type like IList in XAML using the {x:Type} Markup Extension?

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

采纳答案by ageektrapped

Not out of the box, no; but there are enterprising developers out there who have done so.

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

Mike Hillberg at Microsoft played with it in this post, for example. Google has others of course.

例如,微软的 Mike Hillberg 在这篇文章中就使用了它。谷歌当然还有其他的。

回答by Ian Oakes

Not directly in XAML, however you could reference a DataTemplateSelectorfrom XAML to choose the correct template.

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

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

The resource dictionary:

资源字典:

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

The window XAML:

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

The window code behind:

后面的窗口代码:

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

回答by cplotts

aelij (the project coordinator for the WPF Contribproject) has another wayto do it.

aelij(WPF Contrib项目的项目协调员)有另一种方法来做到这一点。

What's even cooler (even though it is sometime off in the future) ... is that XAML 2009 (XAML 2006 is the current version) is going to support this natively. Check out this PDC 2008 sessionfor info on it and more.

更酷的是(即使它在未来的某个时候关闭)...是 XAML 2009(XAML 2006 是当前版本)将在本机支持此功能。查看此PDC 2008 会议以获取有关它的信息及更多信息。

回答by Claudiu Mihaila

You also can wrap your generic class in a derived class that specifies the T

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

public class StringList : List<String>{}

and use StringList from XAML.

并使用 XAML 中的 StringList。

回答by Mike de Klerk

Quite defeats the purpose of a generic, but you could define a class that derives from the generic like so, with the sole purpose of being able to use that type in XAML.

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

public class MyType : List<int> { }

And use it in xaml e.g. like

并在 xaml 中使用它,例如

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