0

我正在尝试创建一个用户控件,它可以让我Dictionary<string,string>在网格中编辑类型的字典(到目前为止只是编辑条目,而不是添加或删除)。

每当我将 DataGrid 绑定到 Dictionary 时,它都会将网格显示为只读,因此我决定创建一个值转换器,它将其转换为ObservableCollection<DictionaryEntry>whereDictionaryEntry只是具有两个属性的类Key,并且Value.

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

我认为这要么是我设置绑定的方式有问题,要么是我的值转换器有问题。如果有人能提供一些启示,那就太棒了。

下面是我能做的最小的演示,它显示了我在做什么。问题再次是当我更改网格中的值时,我的MyDictionaryon myMainViewModel没有更新......永远。为什么?

主视图模型.cs

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

主窗口.xaml

<Window ...>
    <Window.Resources>
        <local:MainViewModel x:Key="MainViewModel"></local:MainViewModel>
    </Window.Resources>
    <StackPanel Name="MainStackPanel" DataContext="{Binding Source={StaticResource MainViewModel}}">
        <local:DictionaryGrid />
        <Button Content="Print Dictionary" Click="PrintDictionary"></Button>        
    </StackPanel>
</Window>

DictionaryGrid.xaml

<UserControl ...>
      <UserControl.Resources>
         <testingGrid:DictionaryToOcConverter x:Key="Converter" />
     </UserControl.Resources>
    <Grid>
        <DataGrid ItemsSource="{Binding MyDictionary, 
                                  Converter={StaticResource Converter}}" 
         />
    </Grid>
</UserControl>

DictionaryToOcConverter.cs

public class DictionaryToOcConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var collection = new ObservableCollection<DictionaryEntry>();
        var dictionary = value as Dictionary<string, string>;
        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<string, string>();

        var entries = value as ObservableCollection<DictionaryEntry>;
        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; }
    }
}
4

1 回答 1

1

这里实际上有两个问题:您的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<DictionaryEntry> MyItems { get; set; } 
    public ViewModel()
    {
        MyItems = new ObservableCollection<DictionaryEntry>();
        MyItems.Add(new DictionaryEntry{K="string1", V="value1"});
        MyItems.Add(new DictionaryEntry { K = "color", V = "red" });
    }

...这与您所拥有的非常接近。Xaml 看起来像这样......

    <DataGrid ItemsSource="{Binding MyItems}" AutoGenerateColumns="True">
    </DataGrid>

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

IEditableObject相对于 DataGrids 的界面上,这是一个已知的“陷阱”,这里有它的描述...... http://blogs.msdn.com/b/vinsibal/archive/2009/04/07/5-随机陷阱与 wpf-datagrid.aspx

它说...

如果您不熟悉 IEditableObject,请参阅这篇 MSDN 文章,其中有很好的解释和代码示例。DataGrid 具有通过 IEditableObject 接口进行事务编辑的功能。当您开始编辑单元格时,DataGrid 会进入单元格编辑模式以及行编辑模式。这意味着您可以取消/提交单元格以及取消/提交行。例如,我编辑单元格 0 并按 Tab 键转到下一个单元格。按 T​​ab 键时提交单元格 0。我开始在单元格 1 中输入并意识到我想取消操作。我按下“Esc”,它恢复单元格 1。我现在意识到我想取消整个操作,所以我再次按下“Esc”,现在单元格 0 恢复到其原始值。

于 2013-07-28T16:54:11.040 回答