it-swarm.com.de

Kann ich einen generischen Typ in XAML (vor .NET 4 Framework) angeben?

In XAML kann ich eine DataTemplate deklarieren, sodass die Vorlage immer verwendet wird, wenn ein bestimmter Typ angezeigt wird. Diese DataTemplate verwendet beispielsweise einen TextBlock, um den Namen eines Kunden anzuzeigen:

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

Ich frage mich, ob es möglich ist, ein DataTemplate zu definieren, das jedes Mal verwendet wird, wenn eine IList <Kunde> angezeigt wird. Wenn der Inhalt eines ContentControls beispielsweise eine ObservableCollection <Kunde> ist, würde er diese Vorlage verwenden.

Ist es möglich, einen generischen Typ wie IList in XAML mit der Markup-Erweiterung {x: Type} zu deklarieren?

72
Matt Hamilton

Nicht aus der Box, nein; Aber es gibt unternehmungslustige Entwickler, die dies getan haben.

Mike Hillberg bei Microsoft spielte beispielsweise in diesem Beitrag mit. Google hat natürlich andere.

24
ageektrapped

Nicht direkt in XAML, Sie können jedoch eine DataTemplateSelector von XAML referenzieren, um die richtige Vorlage auszuwählen.

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

Das Ressourcenwörterbuch:

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

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

Der Fenstercode dahinter:

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;
    }
}
30
Ian Oakes

Sie können Ihre generische Klasse auch in eine abgeleitete Klasse einschließen, die das T angibt

public class StringList : List<String>{}

und verwenden Sie StringList aus XAML.

21
Claudiu Mihaila

aelij (der Projektkoordinator für das WPF Contrib Projekt) hat einen anderen Weg , um dies zu tun.

Was noch cooler ist (auch wenn es irgendwann einmal in der Zukunft los ist) ... ist, dass XAML 2009 (XAML 2006 ist die aktuelle Version) dies nativ unterstützt. Schauen Sie sich diese PDC 2008-Sitzung an für Informationen darüber und mehr.

7
cplotts

Ich glaube, dass dies in anderen Versionen des .NET-Frameworks möglich ist.

Überprüfen Sie die Generics in der XAML-Dokumentation . Sie müssten x:TypeArguments verwenden. Es gibt einige Einschränkungen, lesen Sie zuerst die Dokumentation.

Siehe auch das Argument How to generic type in XAML question in Stackoverflow

0
Ian Ringrose

Quite besiegt den Zweck eines Generikums, aber Sie könnten eine Klasse definieren, die sich vom Generikum ableitet, nur um diesen Typ in XAML verwenden zu können.

public class MyType : List<int> { }

Und verwenden Sie es in xaml, z. mögen

<DataTemplate DataType={x:Type myNamespace:MyType}>
0
Mike de Klerk