Могу ли я указать общий тип в XAML (pre.NET 4 Framework)?

В XAML я могу объявить DataTemplate, чтобы шаблон использовался всякий раз, когда отображается определенный тип. Например, этот DataTemplate будет использовать TextBlock для отображения имени клиента:

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

Мне интересно, можно ли определить DataTemplate, который будет использоваться в любое время, когда IList <Customer> отображается. Поэтому, если ContentControl Content является, скажем, ObservableCollection <Customer> он будет использовать этот шаблон.

Можно ли объявить общий тип типа IList в XAML с помощью расширения {x: Type} Markup Extension?

Ответ 1

Не из коробки, нет; но есть предприимчивые разработчики, которые это сделали.

Майк Хиллберг в Microsoft играл с ним в этот пост, например. Разумеется, у Google есть другие.

Ответ 2

Не в XAML, однако вы можете ссылаться на DataTemplateSelector из XAML, чтобы выбрать правильный шаблон.

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

Ответ 3

Вы также можете обернуть свой общий класс в производном классе, который указывает T

public class StringList : List<String>{}

и используйте StringList из XAML.

Ответ 4

aelij (координатор проекта для проекта WPF Contrib) имеет еще один путь, чтобы сделать это.

Что еще круче (хотя в какой-то момент это когда-то)... что XAML 2009 (XAML 2006 - это текущая версия) будет поддерживать это изначально. Ознакомьтесь с этим сеансом PDC 2008 для получения информации об этом и многом другом.

Ответ 5

Я могу сказать, что в resent версиях .NET Framework это можно сделать.

Проверьте Общие сведения в документации XAML. Вам нужно будет использовать x:TypeArguments; есть некоторые ограничения, поэтому сначала прочтите документацию.

Также см. Как задать аргумент типового типа в XAML на Stackoverflow

Ответ 6

Совершенно поражает цель общего, но вы можете определить класс, который происходит из общего типа, таким образом, с единственной целью - использовать этот тип в XAML.

public class MyType : List<int> { }

И используйте его в xaml, например. как

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