Могу ли я указать универсальный тип в XAML (pre.NET 4 рамки)?


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

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

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

можно ли объявить универсальный тип, например IList в XAML, используя расширение разметки {x:Type}?

6 71

6 ответов:

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

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

не непосредственно в 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;
    }
}

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

public class StringList : List<String>{}

и использовать StringList из XAML.

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

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

Я считаю, что в resent версии .net framework Это можно сделать.

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

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

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

public class MyType : List<int> { }

и использовать его в XAML, например, как

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