2009-04-28 22 views
22

Dictionary<string, int>をWPFのListViewにバインドしたいと思います。私はこのようにして、のDictionaryをデータバインディングメカニズムを介して更新するようにしたいと思います。私はValuesだけをKeysに変更したくありません。 Dictionaryに新しいマッピングを追加することについても気にしません。私はちょうど既存のものを更新したい。WPFで辞書を使用した双方向データバインディング

ItemsSourceの辞書をListViewと設定しても、これは成立しません。 ListViewがEnumeratorを使用してDictionaryの内容にアクセスし、その列挙の要素が不変のKeyValuePairオブジェクトであるために機能しません。

私の現在の調査は、Keysプロパティを使用しようとしています。私はこれをItemsSourceの私のListViewというプロパティに割り当てます。これは私にKeysを表示することができますが、私はのValuesにアクセスするWPFのデータバインディングの仕組みについては十分に分かりません。

私はこの質問を見つけました:Access codebehind variable in XAMLまだギャップを埋めるように見えることはできません。

このアプローチをどのように機能させるか知っていますか? 誰かがより良いアプローチをしていますか?

最後の手段として、私はカスタムオブジェクトを作成してListに貼り付けました。私はDictionaryを再作成/更新しますが、これはビルトインのデータバインディング機能を迂回する方法のようですそれを効果的に活用する。

+1

の独自のバージョンを実装することができますか? – Rauhotz

+0

どうやってそれを2つにするつもりですか?値はTextBoxに表示されていますか? – Ray

+0

@レイ私は私の値のためのカスタムエディタを持っています。 TextBoxを使った例があれば、自分のニーズを満たすことができると確信しています。 –

答えて

17

私はあなたが辞書で何をしたいとは思わないと思います。

  1. あなたが望むように双方向の結合を可能にするつもりはないので辞書がINotifyPropertyChangedのかINotifyCollectionChanged
  2. を実装していないので

あなたの要件に厳密に合っているかどうかはわかりませんが、ObservableCollectionとカスタムクラスを使用します。

私はDataTemplateを使用して、値のバインディングを2通りにする方法を示しています。あなただけObservableCollection<int>

カスタムクラス

public class MyCustomClass 
{ 
    public string Key { get; set; } 
    public int Value { get; set; } 
} 

セットのItemsSource

ObservableCollection<MyCustomClass> dict = new ObservableCollection<MyCustomClass>(); 
dict.Add(new MyCustomClass{Key = "test", Value = 1}); 
dict.Add(new MyCustomClass{ Key = "test2", Value = 2 }); 
listView.ItemsSource = dict; 

XAML

<Window.Resources> 
    <DataTemplate x:Key="ValueTemplate"> 
     <TextBox Text="{Binding Value}" /> 
    </DataTemplate> 
</Window.Resources> 
<ListView Name="listView"> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn CellTemplate="{StaticResource ValueTemplate}"/> 
     </GridView> 
    </ListView.View> 
</ListView> 
を使用することができますので、この実装のキーでもちろん

は、使用されていません

+1

私は、リストビューからの変更をディクショナリに伝播するよりも、ディクショナリの変更をListViewに伝播する心配はあまりありません。 INotifyのインターフェースは、主に前者のことを心配しているようです。 –

+0

はい、そうです。しかし、私は辞書に正しくバインドしようとしましたが、それを動作させることはできませんでした。他に誰かが何か示唆を持っているかどうかを確認します。 – Ray

+0

MyCustomClassはINotifyPropertyChangedを実装する必要があります – MikeT

6

これはちょっとハッキーですが、私はそれを働かせました(私があなたが望むものを理解していると仮定して)。XAMLで

class ViewModel : INotifyPropertyChanged 
{ 
    public ViewModel() 
    { 
     this.data.Add(1, "One"); 
     this.data.Add(2, "Two"); 
     this.data.Add(3, "Three"); 
    } 

    Dictionary<int, string> data = new Dictionary<int, string>(); 
    public IDictionary<int, string> Data 
    { 
     get { return this.data; } 
    } 

    private KeyValuePair<int, string>? selectedKey = null; 
    public KeyValuePair<int, string>? SelectedKey 
    { 
     get { return this.selectedKey; } 
     set 
     { 
      this.selectedKey = value; 
      this.OnPropertyChanged("SelectedKey"); 
      this.OnPropertyChanged("SelectedValue"); 
     } 
    } 

    public string SelectedValue 
    { 
     get 
     { 
      if(null == this.SelectedKey) 
      { 
       return string.Empty; 
      } 

      return this.data[this.SelectedKey.Value.Key]; 
     } 
     set 
     { 
      this.data[this.SelectedKey.Value.Key] = value; 
      this.OnPropertyChanged("SelectedValue"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propName) 
    { 
     var eh = this.PropertyChanged; 
     if(null != eh) 
     { 
      eh(this, new PropertyChangedEventArgs(propName)); 
     } 
    } 
} 

そして:

<Window x:Class="WpfApplication1.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <ListBox x:Name="ItemsListBox" Grid.Row="0" 
      ItemsSource="{Binding Path=Data}" 
      DisplayMemberPath="Key" 
      SelectedItem="{Binding Path=SelectedKey}"> 
     </ListBox> 
     <TextBox Grid.Row="1" 
      Text="{Binding Path=SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/> 
    </Grid> 
</Window> 

Dataプロパティの値がListBoxItemsSourceにバインドされている

は、私が最初のビューモデルクラスを作成しました。質問に記載されているように、この結果、のインスタンスが ListBoxの背後にあるデータとして使用されます。 DisplayMemberPathKeyに設定し、キーの値が ListBoxの各項目の表示値として使用されるようにしました。

あなたが見つけたので、KeyValuePairValueTextBoxのデータとして使用することはできません。これは読み取り専用であるためです。その代わりに、TextBoxは、現在選択されているキーの値を取得して設定できるビューモデルのプロパティにバインドされています(ビューモデルの別のプロパティにListBoxSelectedItemプロパティをバインドすることによって更新されます)。私はこのプロパティをnullableにする必要がありました(KeyValuePairは構造体です)、選択がないときにコードが検出できるようにしなければなりませんでした。

私のテストアプリケーションでは、TextBoxを編集してビューモデルのDictionaryに伝播しているようです。

あなたは何をやっているのですか?それは少しきれいにする必要があるようだが、そうする方法があるかどうかわからない。代わりに

Dictionary<string, int> 

+0

私の状況は少し異なります。Dictionary アイテムをLabelとTextboxの複数のペアとして表示したいとします。あなたは何か考えていますか? – YukiSakura

+0

@YukiSakura辞書に見つかったItemsControlから始め、適切なプロパティにバインドされたLabelとTextBoxを持つようにアイテムテンプレートを設定します。 – Andy

+0

私は試しましたが、実行時に 'TwoWayを読み込み専用のKeyValuePairに使用できません...'というエラーがありました。 – YukiSakura

0

は、あなたが

Dictionary<string, IntWrapperClass>? 

持っIntWrapperClassがINotifyPropertyChangedの実装を持つことができます。次に、リストビュー/リストボックスを辞書内の項目に双方向バインドすることができます。

0

私は上記から派生したものを投稿します。 ObservableCollection<ObservableKvp<MyKeyObject, MyValueObject>>

キーを読み取り専用にすることは、おそらく変更しないでください。これは動作するようにプリズムを必要としています - またはあなたはそれがより良いWPFとObservableDictionaryようなものを使用することはないでしょうINotifyPropertyChanged代わり

public class ObservableKvp<K, V> : BindableBase 
{ 
    public K Key { get; } 

    private V _value; 
    public V Value 
    { 
     get { return _value; } 
     set { SetProperty(ref _value, value); } 
    } 

    public ObservableKvp(K key, V value) 
    { 
     Key = key; 
     Value = value; 
    } 
} 
関連する問題