This article is compatible with the latest version of Silverlight.
Finally we came to the editing part that concerns the DataGrid control in Silverlight. After we took a quick look at the control, learned how to make some basic customizations to it and defined the three types of columns available, now we're going to see how can we edit the information. The DataGrid control has an integrated editing functionality. By double-clicking on a cell you automatically go into edit mode for that cell. If you want to cancel the edit just press Esc and if you want to submit the changes press Enter or change the selection. The purpose of this article is to show how to use this functionality and combine it with some properties and events.
Disabling editing in the DataGrid control
The first question that I have asked myself was - "The DataGrid control has an editing functionality by default, what about if I don't want the information in my grid to be changed?" So I think it's proper to start the article with that. If you want your DataGrid to be read only, you can easily accomplish this by using the IsReadOnly property:
<my:DataGrid x:Name="Foods" IsReadOnly="True">
...
</my:DataGrid>
Each column type also has a IsReadOnly property so if you want only particular columns to be non-editable, set their property to true instead of disabling editing for the whole grid.
Some important events
BeginningEdit - this event is raised when a cell enters into edit mode.
CancellingEdit - this event is raised when a cell leaves edit mode and cancels the changes.
ComittingEdit - this event is raised when a cell leaves edit mode and submits the changes.
On BeginningEdit
For the event handler we have an event argument of type DataGridBeginningEditEventArgs. It contains the column and the row of the cell to be edited. Having access to these column and row we can easily change their visual style, disable the resizing and reordering or something else.
A little more notes about the TemplateColumn and the Editing
As I mentioned in the previous article the TemplateColumn needs also a CellEditingTemplate. If none is defined the CellTemplate will be used instead. So if you want to have an adequate editing functionality in your grid, define one. As in any template it must contain a Layout control in which the other controls will be placed - that's in case you have more than one Silverlight control used in your template, otherwise there is no problem in placing a single control into the DataTemplate. For example:
<my:DataGridTemplateColumn Header="Quantity" >
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="Quantity" Text="{Binding Quantity}" FontFamily="Trebuchet MS" FontSize="11"
Margin="5,5,5,5"></TextBlock>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
<my:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel x:Name="Edit" Orientation="Horizontal">
<TextBlock Text="New value" FontSize="11" Margin="5,5,5,5"></TextBlock>
<TextBox x:Name="EditQuantity1" Text="{Binding Quantity, Mode=TwoWay}" FontFamily="Trebuchet MS"
FontSize="11" Margin="5,5,5,5"></TextBox>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellEditingTemplate>
</my:DataGridTemplateColumn>
The first template contains only one control so it doesn't need a layout control. The EditingTemplate contains a TextBox and aTextBlock, so they must be placed inside a layout control.
On CancellingEdit and On ComittingEdit
For these two we have event arguments of type DataGridEndingEditEventArgs. Except the column and the row of the cell to be edited this type of command arguments contains also the element of the cell that is displayed in edit mode, that means the layout root of the cell template including its child controls. Having this element allows us easily to gather the new information and submit it for example via a web service to a data base. It can be accessed via the EditingElement property.
Another interesting thing is the EditingUnit property. It indicates whether editing is enabled on the cell-level or row-level. I haven't found a way to affect the value of it, so I suppose it will be usable in the next version of the control.
Getting the DataContext of the row on CommitingEdit
Although the DataContext is updated when editing a grid cell (with some exceptions, take a look at the issue section below in the article), the source information should also be updated. When updating information in XML file or in a DataBase we update by a unique value of the element or of the row ( Id for example). That way we are sure that we have updated the value that was changed by the user. To take such information form the DataGrid we're going to use the DataContext for the row, in which the edited cell is placed. For that purpose we use the ComittingEdit event of the control and its event argument. In it as already mentioned can be found the EditingElement property. Its DataContext is the same as the DataContext of the row.
private void Foods_CommittingEdit( object sender, DataGridEndingEditEventArgs e )
{
Nutrition food = ( Nutrition )e.EditingElement.DataContext;
}
In this case the DataContext is of type Nutrition, a class I have created for the examples in this series of articles.
Issues
Here are some issues that I couldn't resolve.
1. The ComittingEdit event is raised two times. The first time the EditingUnit property of the event argument is of type Cell, the second time it's of type Row. I don't know what is the reason for this. The EditingUnit property indicates whether editing is enabled on the cell-level or row-level. I found in the MSDN that the set method of this property is private, so probably it will be a part from one of the features of the DataGrid that will come along with the new version of Silverlight.
2.When I edit a template column and submit the changes the old value of the cell is displayed instead of the new one. After I go again in edit mode for the same cell the new value is bound. This doesn't happen for the other column types.
3.The SelectedIndex property is always equal to -1.
I guess these are things that are to be fixed in the next version of the control. The DataGrid control will surely provide us with a lot of functionality but for now it seems that not everything is implemented yet and the Silverlight team is still working on it. If you happen to find more DataGrid issues you can share them with the community here.
Summary
I hope that this article gave explanations to most of things around the editing in the DataGrid control. Maybe a lot is still unclear, but the control is still unfinished and is yet to be improved. If you have questions I will gladly try to answer them, just post a comments. The next article will be about the row details, a very good feature of the DataGrid, so expect it soon.