为什么CompositeCollection不能Freezable?

时间:2009-07-27 16:05:57

标签: wpf freezable compositecollection

我正在使用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<T> freezable的集合。我没有制作CollectionViews,这使得它不能直接满足我的需求。
  2. MSFT的Sam Bent在上面的链接中说了很多。我还没有找到他的联系方式,但如果我有机会,我打算和他讨论这个问题。
  3. 我目前解决此问题的计划是创建一个具有CompositeCollection和FreezableCollection<T>属性的新集合。我不知道它是否能够正常工作,但我正在考虑这样的事情:

    public class BindableCompositeCollection : FreezableCollection<object>, ICollectionViewFactory
    

    如果有人有更好的选择,我希望听到它!

1 个答案:

答案 0 :(得分:10)

我今晚刚试过这个:

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>

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

编辑:

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