72 votes

Puis-je spécifier un type générique dans XAML (avant le Framework .NET 4) ?

Dans XAML, je peux déclarer un DataTemplate afin que le modèle soit utilisé chaque fois qu'un type spécifique est affiché. Par exemple, ce DataTemplate utilisera un TextBlock pour afficher le nom d'un client :

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

Je me demande s'il est possible de définir un DataTemplate qui sera utilisé à chaque fois qu'un IList<Customer> sera affiché. Ainsi, si le contenu d'un ContentControl est, par exemple, une ObservableCollection<Customer>, ce modèle serait utilisé.

Est-il possible de déclarer un type générique tel qu'IList dans XAML en utilisant l'extension de balisage {x:Type} ? Markup Extension ?

31voto

Ian Oakes Points 5796

Pas directement dans XAML, mais vous pourriez faire référence à un fichier DataTemplateSelector à partir de XAML pour choisir le bon modèle.

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

Le dictionnaire des ressources :

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

La fenêtre 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>

Le code de la fenêtre derrière :

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

24voto

ageektrapped Points 7815

Pas directement, non, mais certains développeurs entreprenants l'ont fait.

Mike Hillberg de Microsoft a joué avec dans ce poste par exemple. Google en a d'autres, bien sûr.

21voto

Claudiu Points 914

Vous pouvez également envelopper votre classe générique dans une classe dérivée qui spécifie la T

public class StringList : List<String>{}

et utiliser StringList depuis XAML.

7voto

cplotts Points 7630

Aelij (le coordinateur du projet pour le Contribution WPF projet) a un autre chemin pour le faire.

Ce qui est encore plus cool (même si c'est un peu loin dans le futur) ... c'est que XAML 2009 (XAML 2006 est la version actuelle) va supporter cela nativement. Regardez ça Session PDC 2008 pour obtenir des informations à ce sujet et plus encore.

0voto

Ian Ringrose Points 19115

Je crois que dans les dernières versions du cadre .net, cela peut être fait.

Vérifiez le Génériques dans la documentation XAML . Vous devez utiliser x:TypeArguments Il y a quelques restrictions, alors lisez d'abord le document.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X