我想在XAML中实例化对象,并重用这些实例。我认为它应该很简单但是我被卡住了,我可能会遗漏一些明显的东西。
假设我想将Cats添加到不同的房间(Room有一个包含Cat类型对象的ObservableCollection)。在UserControl.Resources中,我创建了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>
在我的UserControl中,我想将Cats添加到Rooms:
<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>
将Cat实例添加到ObservableCollection Room.Cats的语法是什么?例如,我想将Cat1和Cat2添加到Room1,将Cat2和Cat3添加到Room2。我完全走错了路吗?
答案 0 :(得分:6)
按照您尝试的方式重复使用单个实例非常棘手。这是因为您通常在XAML中引用单个对象的方式是使用StaticResource
标记扩展,并且您只能使用该标记扩展来设置属性值。
因此,您可以轻松地将Cat
类型的属性设置为Cat
的实例:
<Room Cat="{StaticResource Cat1}"/>
但您无法通过设置属性来填充集合。
令人惊讶的是,答案是直接在XAML中实例化对象,而不是将它们包装在ObjectDataProvider
中。您仍然使用ObjectDataProvider
,但方式不同:
<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>
答案 1 :(得分:3)
根据Heinzi和Robert Rossney的反馈,我提出了以下解决方案,该解决方案适用于我可以在XAML中访问的ObservableCollection和后面的代码:
在代码中我扩展了ObservableCollection,因此我可以在XAML中使用它(在XAML 2009中将不再需要它):
public class CatObservableCollection : ObservableCollection<Cat> { }
在UserControl.Resources的XAML中,我实例化了Cats:
<local:Cat x:Key="Tom" Name="Tom"/>
<local:Cat x:Key="Garfield" Name="Garfield"/>
<local:Cat x:Key="Furball" Name="Furball"/>
收藏品:
<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>
房间现在定义如下:
<local:Room x:Name="Room1" Cats="{StaticResource Room1Collection}"/>
<local:Room x:Name="Room2" Cats="{StaticResource Room2Collection}"/>
Room.Cats是一个ObservableCollection&lt; Cat&gt;
答案 2 :(得分:0)
根据您的具体需求,您可以选择仿制药。要以声明方式使用泛型,必须使用x:TypeArguments Directive。 TypeArguments指令只能与root元素一起使用。所以,你现在必须去寻找松散的XAML文件。可以使用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; }
}
}
窗口类:
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);
}
}
}
因此,包含XAML代码的.txt文件将是:
<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>