I'm trying to create a UserControl, that will let me edit a Dictionary of type Dictionary<string,string>
in a grid (just editing entries so far, not adding or deleting).
Whenever I bind the DataGrid to a Dictionary it shows the grid as read only, so I decieded to create a value converter, that would convert it to an ObservableCollection<DictionaryEntry>
where DictionaryEntry
is just a class with two properties Key
, and Value
.
This works for display the dictionary in the grid, but now when I make changes to the grid, my dictionary is not being updated. I'm unsure why.
I think it's either a problem with the way I have my bindings set up, or my value converter. If anyone could shed some light, that would be fantastic.
Below is the smallest demo I could make that shows what I'm doing. Again the problem is when I change values in the grid, the MyDictionary
on my MainViewModel
is not updated..ever. Why?
MainViewModel.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");
}
}
...
}
MainWindow.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; }
}
}
There's actually two issues here: your
DictionaryEntry
class should implement INotifyPropertyChanged to work correctly with the binding engine, and secondarily it should implement IEditableObject because you want to edit items in a data grid and avoid 'random results'. So your class should look something like this...In your ViewModel (or code behind) you would instantiate it like this...
...which is pretty close to what you have. And the Xaml would look like this...
Those things will bring about the behaviour you are after. I.e., edits will be sticky.
On the
IEditableObject
interface vis-à-vis DataGrids, it's a known 'gotcha' and there's a description of it here... http://blogs.msdn.com/b/vinsibal/archive/2009/04/07/5-random-gotchas-with-the-wpf-datagrid.aspxwhich says...