【问题标题】:Instantiate and reuse instances of objects in XAML在 XAML 中实例化和重用对象的实例
【发布时间】:2010-10-01 14:59:59
【问题描述】:

我想在 XAML 中实例化对象,并重用这些实例。我认为这应该很简单,但我被卡住了,我可能遗漏了一些明显的东西。

假设我想将猫添加到不同的房间(房间有一个包含猫类型对象的 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>

在我的用户控件中,我想将猫添加到房间:

<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。我完全走错了吗?

【问题讨论】:

  • 可能可以通过将&lt;StaticResource ResourceKey="Cat1" /&gt; 添加到您的猫列表中来做到这一点。由于我目前无法对此进行测试,因此我只是将其添加为评论...
  • @Heinzi:我试过了,它可以编译,但是运行时它给出了 XamlParseException:“System.Windows.Data.ObjectDataProvider”类型的对象无法转换为“System.Collections.ObjectModel.ObservableCollection”类型`1[猫]'
  • 我明白了。接下来我要尝试的是 (a) 在 &lt;local:Room.Cats&gt; 内的 XAML 中创建一个 ObservableCollection(请参阅 msdn.microsoft.com/en-us/library/ms668604.aspx 中的“XAML 使用说明”),然后 (b) 将 ObjectDataProvider 替换为 Cat (即&lt;local:Cat Name="Garfield" x:Key="Cat1"&gt;),然后在 ObservableCollection 中添加指向 Cat 的 StaticResource。但是,这将要求您的 Cat 类具有无参数构造函数。

标签: wpf xaml object objectdataprovider instances


【解决方案1】:

以您尝试的方式重用单个实例是很棘手的。这是因为您通常在 XAML 中引用单个对象的方式是使用 StaticResource 标记扩展,并且您只能使用该标记扩展来设置属性值。

因此您可以轻松地将Cat 类型的属性设置为Cat 的实例:

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

但您不能通过设置属性来填充集合。

令人惊讶的是,答案是直接在 XAML 中实例化您的对象,而不是将它们包装在 ObjectDataProviders 中。你仍然使用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>

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      对于您非常具体的需求,您可以选择泛型。要以声明方式使用泛型,您必须使用x:TypeArguments Directive。 TypeArguments 指令只能与根元素一起使用。因此,您现在必须使用松散的 XAML 文件。可以使用 System.Windows.Markup.XamlReader.Load(Stream Stream) method 读取松散的 XAML 文件

      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>
      

      【讨论】:

      • 确保将 Build Action 设置为 Content 并将 Copy to output directory 属性设置为 Always for roomcats.txt。
      猜你喜欢
      • 2010-12-04
      • 1970-01-01
      • 2011-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-04
      相关资源
      最近更新 更多