Monday, September 3, 2007

DataRow.BeginEdit Method

This is the sample code copied from MSDN.

1 private void DemonstrateRowBeginEdit()

2 {

3 DataTable table = new DataTable("table1");

4 DataColumn column = new

5 DataColumn("col1",Type.GetType("System.Int32"));

6 table.RowChanged+=new

7 DataRowChangeEventHandler(Row_Changed);

8 table.Columns.Add(column);

9

10 // Add a UniqueConstraint to the table.

11 table.Constraints.Add(new UniqueConstraint(column));

12

13 // Add five rows.

14 DataRow newRow;

15

16 for(int i = 0;i<5; i++)

17 {

18 // RowChanged event will occur for every addition.

19 newRow= table.NewRow();

20 newRow[0]= i;

21 table.Rows.Add(newRow);

22 }

23 // AcceptChanges.

24 table.AcceptChanges();

25

26 // Invoke BeginEdit on each.

27 Console.WriteLine(

28 "\n Begin Edit and print original and proposed values \n");

29 foreach(DataRow row in table.Rows)

30 {

31

32 row.BeginEdit();

33 row[0]=(int) row[0]+10;

34 Console.Write("\table Original \table" +

35 row[0, DataRowVersion.Original]);

36 Console.Write("\table Proposed \table" +

37 row[0,DataRowVersion.Proposed] + "\n");

38 }

39 Console.WriteLine("\n");

40 // Accept changes

41 table.AcceptChanges();

42 // Change two rows to identical values after invoking BeginEdit.

43 table.Rows[0].BeginEdit();

44 table.Rows[1].BeginEdit();

45 table.Rows[0][0]= 100;

46 table.Rows[1][0]=100;

47 try

48 {

49 /* Now invoke EndEdit. This will cause the UniqueConstraint

50 to be enforced.*/

51 table.Rows[0].EndEdit();

52 table.Rows[1].EndEdit();

53 }

54 catch(Exception e)

55 {

56 // Process exception and return.

57 Console.WriteLine("Exception of type {0} occurred.",

58 e.GetType());

59 }

60 }

61

62 private void Row_Changed(object sender,

63 System.Data.DataRowChangeEventArgs e)

64 {

65 DataTable table = (DataTable) sender;

66 Console.WriteLine("RowChanged " + e.Action.ToString()

67 + "\table" + e.Row.ItemArray[0]);

68 }

The followings are the event sequences I have observed when executing DemonstrateRowBeginEdit method.
  • When line 21 is executed, for each row added, 1 RowChanged event is fired and 'Change' is passed as DataRowChangeEventArgs.Action argument.
  • When line 24 is executed, for each row added, 1 RowChanged event is fired and 'Commit' is passed as DataRowChangeEventArgs.Action argument.
  • When line 41 is executed, for each row modified, 2 RowChanged events are fired and 'Change' and 'Commit' are passed as DataRowChangeEventArgs.Action argument separately.
  • When line 51 is executed, 1 RowChanged event is fired and 'Change' is passed as DataRowChangeEventArgs.Action argument.
  • When line 52 is executed, System.Data.ConstraintException is thrown.
Some other behaviors are observed after the code is modified.
  • If line 32 is commented out, System.Data.VersionNotFoundException is thrown at line 36 for 'There is no Proposed data to access'.
  • If line 32 and line 36 are commented out, when line 33 is executed, 1 RowChanged event is fired and 'Change' is passed as DataRowChangeEventArgs.Action argument. And when line 41 is executed, for each row modified, 1 RowChanged event is fired and 'Commit' is passed as DataRowChangeEventArgs.Action argument.
  • If "Console.WriteLine(table.Rows[0][0]);" is inserted before line 51, default version of the data is accessed(via Reflector) and "100" is printed.
  • If "Console.WriteLine(table.Rows[0][0, DataRowVersion.Current]);" is inserted before line 51, "10" is printed.
  • If "Console.WriteLine(table.Rows[0][0, DataRowVersion.Current]);" is inserted after line 51, "100" is printed.
  • If "Console.WriteLine(table.Rows[0][0, DataRowVersion.Original]);" is inserted after line 51, "10" is printed.
  • If "table.Rows[0].AcceptChanges(); Console.WriteLine(table.Rows[0][0, DataRowVersion.Original]);" is inserted after line 51, "100" is printed.
The experiment confirms the following DataRow behaviors:
  1. DataRow.BeginEdit method temporarily suspends events.
  2. DataRow.EndEdit method invokes 1 RowChanged event.
  3. DataTable.AcceptChanges method invokes 2 RowChanged events for each row modified.
  4. The default version of DataRow is updated after DataRow.EndEdit method is called.
  5. The original version of DataRow is updated after DataRow.AcceptChanges method is called.
So why should I care about BeginEdit method? Without calling BeginEdit method, for each column in a row I modify, one RowChanged event is fired. If 10 columns per row are modified, 10 RowChanged events are fired for every modified row. If the DataTable is updated by a background thread, and is attached to a data-bound control, say, DataGridView, which is controlled by a UI thread. Those updates would cause too many events fired and might result in some weird behaviors of that data-bound control. DataRow.BeginEdit method allows us to suspend events temporarily. After completing modification, we call EndEdit or AcceptChanges method to notify that data-bound control to update changes.

Note: To update a data object bounded to a UI control from a background thread, be sure to read the article first.

No comments: