为什么CompositeCollection不是Freezable?

22

我正在使用MVVM模式编写一个应用程序。通过将视图的DataContext属性设置为我的ViewModel实例,我向视图提供数据。通常情况下,我只是使用绑定并继续进行操作。

最近,我尝试使用ComboBox,并希望在ViewModel提供的集合之外增加一个称为“Select Item”的“额外”元素。

<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版本,并使其成为可冻结对象。但是,这引出了以下问题:
为什么CompositeCollection本身不是Freezable?
我担心通常这些决策都有其原因,而我对Freezable不太了解,无法说出它们为什么没有从中继承。我知道我可以实现这个集合,但是如果我这样做,性能上可能会有明显的差异。
任何帮助将不胜感激。谢谢!
public class BindableCompositeCollection : FreezableCollection<object>, ICollectionViewFactory

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


2
也许这个链接会有帮助:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b15cbd9d-95aa-47c6-8068-7ae9f7dca88a - Arsen Mkrtchyan
也许...这似乎包含了一个微软员工说这是一个bug。有趣。这让我对做这件事感到稍微好一些。不过,我想看看是否有人对性能有任何顾虑。将此记录为答案,以便如果这只是因为有人忽略了CompositeCollection的情况,我可以给你信用。 - Anderson Imes
1
这是与此处概述的基本问题相同,适用于相同解决方法的问题:http://www.codeproject.com/KB/WPF/ArtificialInheritanceCxt.aspx。就个人而言,我更喜欢“spy”技巧。 - Pavel Minaev
1个回答

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>
关键在于将您的服务定位器实例化为静态资源,然后通过它获取到您的视图模型。 使用Unity或任何您想要的DI,服务定位器可以连接到ViewModel的实例。
编辑:
实际上,在我的Silverlight应用程序中,我将服务定位器创建为App.xaml中的静态资源,然后将其他用户控件/窗口/页面的DataContext绑定到服务定位器的ViewModel属性。 即使服务定位器在App.xaml的资源中实例化,对于组合框仍然应该以相同的方式工作。 我希望有Silverlight版本的CompositeCollection可供使用。 这将非常适合我正在处理的应用程序。 :(

根据 Marlon Grech 博客上的最近建议,我们一直想走这条路线。我明天早上会试一下! - Anderson Imes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接