Introduction

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.

 

Building the Sample

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.

 

XAML
Edit|Remove
<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>
Now we enable some other events for cell changing events:
XAML
Edit|Remove
<DataGrid ItemsSource="{Binding MyCollection}" AutoGenerateColumns="False" 
            BeginningEdit="DataGrid_BeginningEdit"  
            CellEditEnding="DataGrid_CellEditEnding"  
            PreparingCellForEdit="DataGrid_PreparingCellForEdit" >
 
When the cell is beggining to edit we keep a copy of the original value:
C#
Edit|Remove
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; 
    } 
}
Each time the text changes, we keep note of the current value:
C#
Edit|Remove
private void MyProperty1_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) 
{ 
    var tb = sender as TextBox; 
    LastChangedValue = Convert.ToInt32(tb.Text); 
}
 
Then finally, when the editing is finished, we save the noted value into the original bound property:
C#
Edit|Remove
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; 
    } 
}
 
Note also we check against the original value to make sure it's changed. If it hasn't we don;t want to write the old original value back into a value that may have since changed in the background.
 

 

 

There's probably a nicer reflective way to do the column/property bit instead of a select statement, but this is a quick solution for a forum question.

 

 

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

 

Source Code Files