22

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

最近,我尝试使用 ViewModel 提供的“Select Item”集合之外的“额外”元素来实现一个 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版本。然而,这引出了以下问题:

为什么 CompositeCollection 首先不是 Freezable ?

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

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

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

更新:

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

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

我目前解决这个问题的计划是创建一个具有 CompositeCollection 和FreezableCollection<T>. 我不知道它是否会起作用,但我正在考虑这样的事情:

public class BindableCompositeCollection : FreezableCollection<object>, ICollectionViewFactory

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

4

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

于 2009-09-17T03:38:47.347 回答