【问题标题】:Why is CompositeCollection not Freezable?为什么 CompositeCollection 不可冻结?
【发布时间】:2009-07-27 16:05:57
【问题描述】:

我正在使用 MVVM 模式编写应用程序。我通过将视图的 DataContext 属性设置为 ViewModel 的实例来向视图提供数据。一般来说,我只是从那里使用 Binding 并按我的方式行事。

最近,我尝试使用 ViewModel 提供的“选择项目”集合之外的“额外”元素来实现 ComboBox。

<ComboBox>    
    <ComboBox.ItemsSource>    
        <CompositeCollection>
           <ComboBoxItem IsEnabled="False">Select Item</ComboBoxItem>
           <CollectionContainer Collection="{Binding MyItemsCollection}" />    
        </CompositeCollection>
    </ComboBox.ItemsSource>
</ComboBox>

问题是,CompositeCollection 不是 Freezable:Freezable Objects Overview。这只会导致静态 ComboBoxItem 出现,而​​我的绑定表达式没有任何结果。

我对这个问题的最初反应是实现我自己的 CompositeCollection 版本, Freezable。不过,这引出了以下问题:

为什么 CompositeCollection 一开始就不是 Freezable?

我担心的是,这些决定通常是有原因的,我觉得我对 Freezable 了解得不够多,无法说出他们为什么不继承它。我知道我可以实现这个集合,但我担心如果我这样做会在性能上产生可衡量的差异。

任何帮助将不胜感激。谢谢!

另外:请注意,我意识到我可以插入 Null 或其他一些特殊值,并提供模板或 valueconverter 来做我想做的事。这不是我感兴趣的问题……只是上面加粗的问题。

更新:

在 ArsenMkrt 的评论带来的一些进一步研究之后,我相信这实际上是一个疏忽。证据是这样的:

  1. 有一个名为FreezableCollection&lt;T&gt; 的集合可冻结的。它不会产生 CollectionViews,这使得它不适合我的需求。
  2. MSFT 的 Sam Bent 在上面的链接中说了很多。我还没有找到他的联系方式,但如果有机会,我打算和他讨论一下。

我目前解决此问题的计划是使用 CompositeCollection 和 FreezableCollection&lt;T&gt; 的属性创建一个新集合。我不知道它是否会起作用,但我正在考虑这样的事情:

public class BindableCompositeCollection : FreezableCollection<object>, ICollectionViewFactory

如果有人有更好的选择,我想听听!

【问题讨论】:

  • 也许...它似乎包含一位 MSFT 员工说这是一个错误。有趣的。这样做让我感觉好一点。不过,我想看看是否有人对性能有任何担忧。将此作为答案记录下来,如果事实证明这完全是因为有人忽略了 CompositeCollection 的这种情况,我可以给你信用。
  • 这与此处概述的基本问题相同,适用的解决方法相同:codeproject.com/KB/WPF/ArtificialInheritanceCxt.aspx。就个人而言,我更喜欢“间谍”把戏。

标签: wpf freezable compositecollection


【解决方案1】:

我今晚刚试过这个:

public class State
{
    public string Code { get; set; }
    public string Name { get; set; }
}

public class MyWindowViewModel
{
    ObservableCollection<State> _states = new ObservableCollection<State>
    {
        new State { Code = "FL", Name = "Florida" },
        new State { Code = "CA", Name = "California" },
    };

    public ObservableCollection<State> States
    {
        get
        {
            return _states;
        }
    }
}
<Window x:Class="WpfApplication1.MyWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:app="clr-namespace:WpfApplication1"
        Title="Window1"
        Height="300"
        Width="300">

  <Window.Resources>
    <app:ServiceLocator x:Key="Locator" />
  </Window.Resources>

  <StackPanel>
    <ComboBox x:Name="TestCombo" SelectedIndex="0" DisplayMemberPath="Name" SelectedValuePath="Code">
      <ComboBox.ItemsSource>
        <CompositeCollection>
          <app:State Code="" Name="Select a state..." />
          <app:State Code="TX" Name="Texas" />
          <CollectionContainer Collection="{Binding Source={StaticResource Locator}, Path=MyWindowViewModel.States}" />
        </CompositeCollection>
      </ComboBox.ItemsSource>
    </ComboBox>
  </StackPanel>
</Window>

这里的关键是创建一个服务定位器实例作为静态资源,然后通过它来访问您的视图模型。服务定位器可以使用 Unity 或任何您想要的 DI 连接到 ViewModel 的实例。

编辑:

实际上,在我的 silverlight 应用程序中,我将服务定位器创建为 App.xaml 中的静态资源,然后将我的其他 UserControls/Windows/Pages DataContext 绑定到服务定位器的 ViewModel 属性。即使在 App.xaml 的资源中实例化了服务定位器,它仍应以相同的方式为组合框工作。我希望有一个可以使用的 CompositeCollection 的 Silverlight 版本。这对我正在开发的应用程序非常有用。 :(

【讨论】:

  • 根据 Marlon Grech 博客上最近的一些建议,我们一直打算走这条路。我早上试试这个!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多