My propblem is that DataGrid sends new value set by user with GUI only when the selected line is changed. When I modify value in form and press "Enter" to confirm input, everything works fine (because "Enter" moves selection to next line). But when I modify value in cell and press with mouse to any other cell in current row, new value is assigned to cell but not sent to binded object. In debugger I see that converter's ConvertBack method is called but Field.Value property setter is not! Field.Value property setter breakpoint fires only after row selection change. How can I force my Model object value change after cell edit finish, not row selection changed?
DataGrid's style:
<Style x:Key="ElementDataGridStyle" TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="False"/>
<Setter Property="HeadersVisibility" Value="Column"/>
<Setter Property="SelectionUnit" Value="Cell"/>
<Setter Property="CellStyle">
<Setter.Value>
<Style TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="true">
<Setter Property="Background" Value="LightGray"/>
</Trigger>
</Style.Triggers>
<EventSetter Event="Loaded" Handler="ElementDataGridStyleCellStyle_Loaded"/>
</Style>
</Setter.Value>
</Setter>
</Style>
Code that binds DataGrid to my Model
private void SetDataGridContent(DataGrid grid, Core.Item.ItemCollection collection)
{
grid.Columns.Clear();
if (collection != null)
{
for (int i = 0; i < collection.FieldProps.Count; i++)
{
Core.FieldProp prop = collection.FieldProps[i];
if (prop.VisualName != null)
{
MultiBinding multiBinding = new MultiBinding()
{
Converter = new Visual.FieldValueConverter()
};
multiBinding.Bindings.Add(new Binding($"Fields[{i}]"));
multiBinding.Bindings.Add(new Binding($"Fields[{i}].Value"));
DataGridTextColumn column = new DataGridTextColumn
{
Binding = multiBinding,
Header = prop.VisualName,
IsReadOnly = !prop.UIEditable,
};
SetColumnFieldIndex(column, i);
grid.Columns.Add(column);
}
}
}
grid.ItemsSource = collection;
}
Fields - is ObservableCollection successor
sealed class FieldCollection : ObservableCollection<Field>
Field class implements INotifyPropertyChanged interface
public class Field : INotifyPropertyChanged
{
private string _value;
public string Value
{
get => _value;
set
{
if (_value != value)
{
Modify(value);
NotifyPropertyChanged();
}
}
}
private void Modify(string value)
{
_value = value;
}
protected void NotifyPropertyChanged([CallerMemberName]string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Value converter looks like this:
class FieldValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[1];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
object[] result = new object[2];
result[0] = Binding.DoNothing; //DependencyProperty.UnsetValue;
result[1] = value;
return result;
}
}