Pregunta

Quiero crear instancias de objetos en XAML, y reutilizar estos casos. Creo que debería ser simple, pero estoy atascado, probablemente estoy perdiendo algo obvio.

Say Quiero añadir gatos a diferentes habitaciones (habitación tiene una ObservableCollection que contiene objetos de tipo gato). En los UserControl.Resources creo 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>

En mi UserControl Quiero añadir los gatos de las habitaciones:

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

¿Cuál es la sintaxis para agregar las instancias de Cat a los Room.Cats ObservableCollection? Por ejemplo, quiero añadir Cat1 y Cat2 a Room1, y Cat2 y Cat3 a Room2 ¿Te. ¿Estoy completamente en el camino equivocado?

¿Fue útil?

Solución 2

Con base en la retroalimentación de Heinzi y Robert Rossney me ocurrió la siguiente solución que funciona con un ObservableCollection que pueden acceder en XAML y código detrás:

En el código que se extendía ObservableCollection para que pueda usarlo en XAML (esto ya no será necesario en XAML 2009):

public class CatObservableCollection : ObservableCollection<Cat> { }

En XAML en los UserControl.Resources que instanciar los gatos:

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

Las colecciones:

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

Las habitaciones están definidos de la siguiente manera:

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

Room.Cats es un ObservableCollection

Otros consejos

reutilización de sesiones individuales de la manera que estamos tratando de hacer es complicado. Esto se debe a la forma en que generalmente se comunica objetos individuales en XAML es con la extensión StaticResource marcado, y sólo se puede utilizar esa extensión de marcado para establecer un valor de propiedad.

Así se pueden crear fácilmente una propiedad de tipo Cat a una instancia de un Cat:

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

pero no se puede rellenar una colección mediante el establecimiento de una propiedad.

La respuesta, sorprendentemente, es crear instancias de los objetos directamente en XAML en lugar de envolverlos en ObjectDataProviders. Todavía se utiliza el ObjectDataProvider, pero de manera diferente:

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

Para sus necesidades muy específicas, que no vaya para los genéricos. Y utilizar los genéricos de forma declarativa, usted tiene que utilizar x: Directiva TypeArguments. TypeArguments Directiva sólo se puede utilizar con el elemento raíz. Por lo tanto, usted tiene que ir ahora para archivo XAML suelto. Un archivo XAML suelto puede ser leído utilizando 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; }
    }
}

clase Window:

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

Por lo tanto, el archivo .txt que contiene el código XAML sería:

<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>
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top