22

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 のみが表示され、バインディング式の結果は表示されません。

この問題に対する私の最初の反応は、 Freezableである CompositeCollection の独自のバージョンを実装することでした。しかし、これは次の疑問を投げかけます。

そもそも CompositeCollection が Freezable でないのはなぜですか?

私の懸念は、一般的にこれらの決定には理由があり、Freezable を継承しなかった理由を説明するのに十分な知識がないと感じていることです。このコレクションを実装できることはわかっていますが、実装した場合、パフォーマンスに測定可能な違いが生じるのではないかと心配しています。

どんな助けでも大歓迎です。ありがとう!

また、Nullまたはその他の特別な値を挿入し、テンプレートまたは値コンバーターを提供して、必要なことを実行できることを認識していることに注意してください。これは私が興味を持っている質問ではありません...上記の太字の質問のみです。

アップデート:

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 に答える