当DataGrid发生更改时,为什么我的ViewModel中的属性没有更新?

我正在尝试创建一个UserControl,它允许我在网格中编辑Dictionary类型的Dictionary (只编辑条目到目前为止,不添加或删除)。

每当我将DataGrid绑定到Dictionary时,它将网格显示为只读,因此我决定创建一个值转换器,将其转换为ObservableCollection ,其中DictionaryEntry只是一个具有两个属性KeyValue

这适用于在网格中显示字典,但现在当我对网格进行更改时,我的字典没有被更新。 我不确定为什么。

我认为这是我设置绑定的方式或我的值转换器的问题。 如果有人能够发光,那就太棒了。

下面是我能做的最小的演示,它展示了我正在做的事情。 问题是当我更改网格中的值时,我的MainViewModel上的MyDictionary不会更新。 为什么?

MainViewModel.cs

 public class MainViewModel : INotifyPropertyChanged { public MainViewModel() { _myDictionary = new Dictionary() { {"Key1", "Value1"}, {"Key2", "Value2"}, {"Key3", "Value3"} }; } private Dictionary _myDictionary; public Dictionary MyDictionary { get { return _myDictionary; } set { if (_myDictionary == value) return; _myDictionary = value; OnPropertyChanged("MyDictionary"); } } ... } 

MainWindow.xaml

          

DictionaryGrid.xaml

         

DictionaryToOcConverter.cs

 public class DictionaryToOcConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var collection = new ObservableCollection(); var dictionary = value as Dictionary; if (dictionary != null) { foreach (var kvp in dictionary) collection.Add(new DictionaryEntry { Key = kvp.Key, Value = kvp.Value }); } return collection; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var dictionary = new Dictionary(); var entries = value as ObservableCollection; if (entries != null) { foreach (var entry in entries) dictionary.Add(entry.Key, entry.Value); } return dictionary; } public class DictionaryEntry { public string Key { get; set; } public string Value { get; set; } } } 

这里实际上有两个问题:你的DictionaryEntry类应该实现INotifyPropertyChanged以正确使用绑定引擎,其次它应该实现IEditableObject,因为你想编辑数据网格中的项目并避免“随机结果”。 所以你的课应该看起来像这样……

 public class DictionaryEntry : INotifyPropertyChanged, IEditableObject { private string _k; [Description("The key")] public string K { [DebuggerStepThrough] get { return _k; } [DebuggerStepThrough] set { if (value != _k) { _k = value; OnPropertyChanged("K"); } } } private string _v; [Description("The value")] public string V { [DebuggerStepThrough] get { return _v; } [DebuggerStepThrough] set { if (value != _v) { _v = value; OnPropertyChanged("V"); } } } #region INotifyPropertyChanged Implementation public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string name) { var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null); if (handler != null) { handler(this, new PropertyChangedEventArgs(name)); } } #endregion #region IEditableObject public void BeginEdit() { // implementation goes here } public void CancelEdit() { // implementation goes here } public void EndEdit() { // implementation goes here } #endregion } 

在你的ViewModel(或后面的代码)你会像这样实例化它…

  public ObservableCollection MyItems { get; set; } public ViewModel() { MyItems = new ObservableCollection(); MyItems.Add(new DictionaryEntry{K="string1", V="value1"}); MyItems.Add(new DictionaryEntry { K = "color", V = "red" }); } 

…这非常接近你所拥有的。 Xaml看起来像这样……

    

那些事情会带来你所追求的行为。 即,编辑将是粘性的。

在相对于DataGrids的IEditableObject接口上,它是一个已知的’gotcha’,这里有一个描述… http://blogs.msdn.com/b/vinsibal/archive/2009/04/07/5 -random-陷阱,用最WPF的datagrid.aspx

哪说……

如果您不熟悉IEditableObject,请参阅此MSDN文章,其中包含一个很好的解释和代码示例。 DataGrid已经通过IEditableObject接口实现了事务编辑function。 当您开始编辑单元格时,DataGrid将进入单元格编辑模式以及行编辑模式。 这意味着您可以取消/提交单元格以及取消/提交行。 例如,我编辑单元格0并按Tab键到下一个单元格。 按Tab键时会提交单元格0。 我开始在单元格1中输入并意识到我想取消操作。 我按’Esc’恢复单元格1.我现在意识到我要取消整个操作,所以我再次按’Esc’,现在单元格0恢复到原始值。