WPFでDictionary<string, int>
をListView
にバインドしたいのですが。 Values
のDictionary
がデータバインディングメカニズムを介して更新されるように、これを実行したいと思います。 Keys
を変更したくないのは、Values
だけです。また、Dictionary
に新しいマッピングを追加することも気にしません。既存のものを更新したいだけです。
辞書をItemsSource
のListView
として設定しても、これは達成されません。 ListView
はEnumeratorを使用してDictionary
のコンテンツにアクセスし、その列挙の要素は不変のKeyValuePair
オブジェクトであるため、機能しません。
現在の調査では、Keys
プロパティを使用しようとしています。これをItemsSource
のListView
プロパティに割り当てます。これによりKeys
を表示できますが、Values
内のDictionary
にアクセスするためのWPFのデータバインディングメカニズムについて十分に理解していません。
私はこの質問を見つけました: XAMLのAccess codebehind変数 ですが、それでもギャップを埋めることができないようです。
このアプローチを機能させる方法を知っている人はいますか?誰かがより良いアプローチをしていますか?
最後の手段として、カスタムオブジェクトをビルドしてList
に貼り付け、そこからDictionary
を再作成/更新できるように思えますが、これは、ビルドされたオブジェクトを回避する方法のようですデータバインディング機能を有効に活用するのではなく、.
辞書であなたがやりたいことをできるようになるとは思いません。
それが要件に正確に適合するかどうかはわかりませんが、ObservableCollection
とカスタムクラスを使用します。
DataTemplateを使用して、値のバインディングを双方向にする方法を示しています。
もちろん、この実装ではKeyは使用されないため、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>
これは少しハックですが、私はそれを機能させました(私があなたが何を望んでいるか理解していると仮定します)。
最初にビューモデルクラスを作成しました。
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));
}
}
}
そして、XAMLで:
<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
プロパティの値は、ItemsSource
のListBox
にバインドされます。質問で述べたように、これはKeyValuePair<int, string>
のインスタンスをListBox
の背後のデータとして使用することになります。 DisplayMemberPath
をKey
に設定して、キーの値がListBox
の各項目の表示値として使用されるようにします。
ご覧のとおり、Value
のKeyValuePair
をTextBox
のデータとして使用することはできません。これは読み取り専用だからです。代わりに、TextBox
は、現在選択されているキーの値を取得および設定できるビューモデルのプロパティにバインドされます(これは、SelectedItem
のListBox
プロパティをビューモデルの別のプロパティにバインドすることによって更新されます)。 (KeyValuePair
は構造体であるため)このプロパティをnullに設定できるようにして、選択がない場合にコードで検出できるようにしました。
私のテストアプリでは、これにより、ビューモデルのTextBox
に伝達されるDictionary
への編集が発生するようです。
それは多かれ少なかれあなたが目指していることですか?少しすっきりしているように見えますが、どうすればいいのかわかりません。
上記から導き出したものを投稿するだけです。以下をObservableCollection<ObservableKvp<MyKeyObject, MyValueObject>>
キーはおそらく変更すべきではないため、キーを読み取り専用にしました。これを実行するにはPrismが必要です-または、代わりに独自のバージョンの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;
}
}
の代わりに
Dictionary<string, int>
、できますか
Dictionary<string, IntWrapperClass>?
IntWrapperClassにINotifyPropertyCHangedを実装させます。次に、リストビュー/リストボックスの双方向バインドを辞書内のアイテムに設定できます。