Question

Je veux instancier des objets en XAML, et réutiliser ces instances. Je pense que ce devrait être simple mais je suis coincé, je suis probablement manque quelque chose évidente.

Disons que je veux ajouter Chats à différentes chambres (chambre dispose d'un récipient contenant un ObservableCollection de type Cat). Dans les UserControl.Resources je crée ObjectDataProviders:

<ObjectDataProvider x:Key="Cat1" ObjectType="{x:Type local:Cat}">
    <ObjectDataProvider.ConstructorParameters>
        <System:String>Tom</System:String>
    </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="Cat2" ObjectType="{x:Type local:Cat}">
    <ObjectDataProvider.ConstructorParameters>
        <System:String>Garfield</System:String>
    </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="Cat3" ObjectType="{x:Type local:Cat}">
    <ObjectDataProvider.ConstructorParameters>
        <System:String>Furball</System:String>
    </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

Dans mon UserControl Je veux ajouter les chats aux Chambres:

<local:Room x:Name="Room1">
    <local:Room.Cats>

    </local:Room.Cats>
<local:Room>
<local:Room x:Name="Room2">
    <local:Room.Cats>

    </local:Room.Cats>
<local:Room>

Quelle est la syntaxe pour ajouter les instances de Cat aux Room.Cats de ObservableCollection? Par exemple, je veux ajouter Cat1 et Cat2 à CH1 et Cat2 et Cat3 à Room2. Suis-je complètement sur la mauvaise voie?

Était-ce utile?

La solution 2

D'après les commentaires de Heinzi et Robert Rossney je suis venu avec la solution suivante qui fonctionne avec un ObservableCollection que je peux accéder en XAML et le code derrière:

Dans le code I étendu ObservableCollection pour que je puisse l'utiliser en XAML (ce ne sera plus nécessaire en XAML 2009):

public class CatObservableCollection : ObservableCollection<Cat> { }

En XAML dans les UserControl.Resources j'instancier les chats:

<local:Cat x:Key="Tom" Name="Tom"/>
<local:Cat x:Key="Garfield" Name="Garfield"/>
<local:Cat x:Key="Furball" Name="Furball"/>

Les collections:

<local:CatObservableCollection x:Key="Room1Collection">
    <StaticResourceExtension ResourceKey="Tom"/>
    <StaticResourceExtension ResourceKey="Garfield"/>
</local:CatObservableCollection>
<local:CatObservableCollection x:Key="Room2Collection">
    <StaticResourceExtension ResourceKey="Garfield"/>
    <StaticResourceExtension ResourceKey="Furball"/>
</local:CatObservableCollection>

Les chambres sont désormais définies comme suit:

<local:Room x:Name="Room1" Cats="{StaticResource Room1Collection}"/>
<local:Room x:Name="Room2" Cats="{StaticResource Room2Collection}"/>

Room.Cats est un ObservableCollection

Autres conseils

Réutiliser des cas individuels comme vous essayez de le faire est délicat. En effet, la façon dont vous faites référence généralement des objets uniques en XAML est avec l'extension de balisage StaticResource, et vous ne pouvez utiliser cette extension de balisage pour définir une valeur de la propriété.

Vous pouvez facilement définir une propriété de type Cat à une instance d'un Cat:

<Room Cat="{StaticResource Cat1}"/>

mais vous ne pouvez pas remplir une collection en définissant une propriété.

La réponse, de façon surprenante, est à la place instancier vos objets directement en XAML de les envelopper dans ObjectDataProviders. Vous utilisez toujours le ObjectDataProvider, mais différemment:

<Window x:Class="ObjectDataProviderDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:local="clr-namespace:ObjectDataProviderDemo" 
        xmlns:Collections="clr-namespace:System.Collections;assembly=mscorlib" 
        Title="MainWindow" 
        Height="350" 
        Width="525">
    <Window.Resources>
        <local:Cat x:Key="Tom" Name="Tom"/>
        <local:Cat x:Key="Garfield" Name="Garfield"/>
        <local:Cat x:Key="Furball" Name="Furball"/>
        <Collections:ArrayList x:Key="CatList1">
            <ObjectDataProvider ObjectInstance="{StaticResource Tom}" />
            <ObjectDataProvider ObjectInstance="{StaticResource Garfield}" />
            <ObjectDataProvider ObjectInstance="{StaticResource Furball}" />
        </Collections:ArrayList>
        <Collections:ArrayList x:Key="CatList2">
            <ObjectDataProvider ObjectInstance="{StaticResource Tom}" />
            <ObjectDataProvider ObjectInstance="{StaticResource Furball}" />
        </Collections:ArrayList>
        <DataTemplate x:Key="CatTemplate">
            <TextBlock Text="{Binding Name}" />
        </DataTemplate>
    </Window.Resources>
    <StackPanel>
        <ListBox ItemsSource="{StaticResource CatList1}" 
                 ItemTemplate="{StaticResource CatTemplate}"/>
        <ListBox ItemsSource="{StaticResource CatList2}"
                 ItemTemplate="{StaticResource CatTemplate}" />
    </StackPanel>
</Window>

Pour vos besoins spécifiques, vous n'allez pour les médicaments génériques. Et d'utiliser les médicaments génériques déclarative, vous devez utiliser x: TypeArguments directive . TypeArguments directive peut être utilisé uniquement avec l'élément racine. Donc, vous avez d'aller maintenant pour le fichier XAML lâche. Un fichier lâche XAML peut être lu en utilisant System.Windows.Markup.XamlReader.Load(Stream Stream) method

Cat.cs:

using System;

namespace WpfCollection._3840371
{
    public class Cat
    {
        public Cat() { }

        public Cat(String name, String color) { Name = name; Color = color; }

        public String Name { get; set; }
        public String Color { get; set; }
    }
}

Room.cs:

using System;
using System.Collections.ObjectModel;

namespace WpfCollection._3840371
{
    public class Room<T> where T : System.Windows.Data.ObjectDataProvider
    {
        public Room()
        {
            Cats = new ObservableCollection<T>();
        }

        public ObservableCollection<T> Cats { get; set; }
    }
}

classe de fenêtre:

namespace WpfCollection._3840371
{
    /// <summary>
    /// Interaction logic for Win3840371.xaml
    /// </summary>
    public partial class Win3840371 : Window
    {
        public Win3840371()
        {
            InitializeComponent();

            Room<ObjectDataProvider> kitchenRoom;
            using (FileStream fs = new FileStream(@"3840371/roomcats.txt", FileMode.Open))
            {
                kitchenRoom = (Room<ObjectDataProvider>)XamlReader.Load(fs);
            }

            foreach (ObjectDataProvider o in kitchenRoom.Cats)
                Debug.WriteLine(((Cat)o.Data).Name + " : " + ((Cat)o.Data).Color);
        }
    }
}

Ainsi, votre fichier txt contenant du code XAML serait:

<local:Room 
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            xmlns:System="clr-namespace:System;assembly=mscorlib"
            xmlns:local="clr-namespace:WpfCollection._3840371;assembly=WpfCollection"
            x:Key="UpperRoom" x:TypeArguments="ObjectDataProvider">
            <local:Room.Cats>
                <ObjectDataProvider x:Key="Cat1" ObjectType="{x:Type local:Cat}">
                    <ObjectDataProvider.ConstructorParameters>
                        <System:String>Tom</System:String>
                        <System:String>Red</System:String>
                    </ObjectDataProvider.ConstructorParameters>
                </ObjectDataProvider>
                <ObjectDataProvider x:Key="Cat2" ObjectType="{x:Type local:Cat}">
                    <ObjectDataProvider.ConstructorParameters>
                        <System:String>Rubia</System:String>
                        <System:String>Brown</System:String>
                    </ObjectDataProvider.ConstructorParameters>
                </ObjectDataProvider>
            </local:Room.Cats>
        </local:Room>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top