This sample shows how to "freeze" the value in a DataGrid cell, while you edit it. Then update to the inputted value, or revert to the current live value.
Just download, unzip, open and run!
Description
When you bind a DataGrid to a collection of data, if you have implemented INotifyPropertyChanged correctly, you can watch live data changes show in the DataGrid. However, if you then try to edit this data, while other background processes are still updating the value, then you may be unable to change the value in time.
What happens to that changed value, and how the code behind handles changes and updates is another story, but this sample shows how to suspend incoming changes, make the change and save that change back to the underlying class.
First of all, we have to stop the updates reflecting in the edit mode. This is done by making the binding one way, and handling changes with a TextChanged event instead of binding back to source.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyProperty1}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate >
<TextBox Text="{Binding MyProperty1, Mode=OneTime}" TextChanged="MyProperty1_TextChanged"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding MyProperty1}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate > <TextBox Text="{Binding MyProperty1, Mode=OneTime}" TextChanged="MyProperty1_TextChanged"/> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate>
<DataGrid ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False"
BeginningEdit="DataGrid_BeginningEdit"
CellEditEnding="DataGrid_CellEditEnding"
PreparingCellForEdit="DataGrid_PreparingCellForEdit" >
<DataGrid ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False" BeginningEdit="DataGrid_BeginningEdit" CellEditEnding="DataGrid_CellEditEnding" PreparingCellForEdit="DataGrid_PreparingCellForEdit" >
private void DataGrid_PreparingCellForEdit(object sender, System.Windows.Controls.DataGridPreparingCellForEditEventArgs e) { var obj = e.EditingElement.DataContext as MyClass; switch (e.Column.Header.ToString()) { case "Col1": OriginalValue = obj.MyProperty1; break; } }
private void DataGrid_PreparingCellForEdit(object sender, System.Windows.Controls.DataGridPreparingCellForEditEventArgs e) { var obj = e.EditingElement.DataContext as MyClass; switch (e.Column.Header.ToString()) { case "Col1": OriginalValue = obj.MyProperty1; break; } }
private void MyProperty1_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { var tb = sender as TextBox; LastChangedValue = Convert.ToInt32(tb.Text); }
private void MyProperty1_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { var tb = sender as TextBox; LastChangedValue = Convert.ToInt32(tb.Text); }
private void DataGrid_CellEditEnding(object sender, System.Windows.Controls.DataGridCellEditEndingEventArgs e) { var obj = e.EditingElement.DataContext as MyClass; switch (e.Column.Header.ToString()) { case "Col1": if (OriginalValue != LastChangedValue) obj.MyProperty1 = LastChangedValue; break; } }
private void DataGrid_CellEditEnding(object sender, System.Windows.Controls.DataGridCellEditEndingEventArgs e) { var obj = e.EditingElement.DataContext as MyClass; switch (e.Column.Header.ToString()) { case "Col1": if (OriginalValue != LastChangedValue) obj.MyProperty1 = LastChangedValue; break; } }
To test
1. Watch the value increase every 3 seconds
2. Click into edit mode, observe the value NOT changing every 3 seconds
3. Press escape or click off the box with no changes, note the value shows the current live value again (which should now be more that when you started editing)
4. Repeat steps 1 & 2, but this time make a change (change it to 99) then press enter or click away
5. Note the value is now as changed and increasing from that new value
