soberga soberga - 2 months ago 17
C# Question

Reject changes on a single DataColumn in a DataRow

I want to reject changes made to a single DataColumn on a DataRow within a DataTable.

I made this test example:

DataTable table = new DataTable();
table.Columns.Add("testColumn1");
table.Columns.Add("testColumn2");

DataRow row = table.NewRow();
row["testColumn1"] = "This change should be preserved";
row["testColumn2"] = "This change should be rejected";
table.Rows.Add(row);

row.RejectChanges();


This rejects all changes made to the row. In my case the user might have some unsaved changes in one of the other columns, so using this will not work for this scenario.

I am looking for a similar functionality that reverts changes for "testcolumn2" only, for example:

row["testColumn2"].RejectChanges();


I looked up the documentation for the DataColumn class and could not find any similar method to DataRow.RejectChanges:

https://msdn.microsoft.com/en-us/library/system.data.datacolumn(v=vs.110).aspx

Is this possible to do with the C# framework or do I have to use an alternative solution?

Alternative solutions are also appreciated.

Answer

You can use the event DataTable.ColumnChanging. This triggers every time a change is made to a DataColumn in the table.

table.ColumnChanging += OnColumnChanging;

The method OnColumnChanging checks that the column name equals the column I want to backup, and that the call is not coming from the "revert value" part of the code (refer to the boolean isRevertingChanges).

If both of these are true, it creates a backup column (This is skipped if it already exists). Finally it writes the value that is about to be overwritten to the backup column on the row.

private bool isRevertingChanges;

void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
{
    if (!isRevertingChanges && e.Column.ColumnName.Equals(TestColumn2))
    {
        if (!e.Row.Table.Columns.Contains(TestColumn2Backup))
            e.Row.Table.Columns.Add(TestColumn2Backup);

        e.Row[TestColumn2Backup] = e.Row[TestColumn2];
    }
}

Since the criteria for reverting changes is irrelevant in this case I have replaced it with if(true) so the revert-part of the code is triggered every time.

First it sets the isRevertingChanges variable to true (this is to prevent OnColumnChanging() from making a backup of the value that is being reverted), then it reverts the column back to its original value and finally it sets isRevertingChanges back to false so OnColumnChanging() will continue backing up values every time the column change.

if (true)
{
    isRevertingChanges = true;
    row[TestColumn2] = row[TestColumn2Backup];
    isRevertingChanges = false;
}

Here is the full source code:

[TestClass]
public class RejectDataColumnChanges
{
    private bool isRevertingChanges;

    private const string TestColumn1 = "testColumn1";
    private const string TestColumn2 = "testColumn2";
    private const string TestColumn2Backup = "testColumn2Backup";

    private const string PreservedMessage = "This change should be preserved";
    private const string RejectedMessage = "This change should be rejected";

    [TestMethod]
    public void RejectDataColumnChangesTest()
    {
        DataTable table = new DataTable("testTable1");
        table.Columns.Add(TestColumn1);
        table.Columns.Add(TestColumn2);

        DataRow row = table.NewRow();
        row[TestColumn1] = PreservedMessage;
        row[TestColumn2] = PreservedMessage;
        table.Rows.Add(row);

        table.ColumnChanging += OnColumnChanging;

        row[TestColumn2] = RejectedMessage;

        Assert.AreEqual(PreservedMessage, row[TestColumn1]);
        Assert.AreEqual(RejectedMessage, row[TestColumn2]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2Backup]);

        if (true)
        {
            isRevertingChanges = true;
            row[TestColumn2] = row[TestColumn2Backup];
            isRevertingChanges = false;
        }

        Assert.AreEqual(PreservedMessage, row[TestColumn1]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2]);
        Assert.AreEqual(PreservedMessage, row[TestColumn2Backup]);
    }

    void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
    {
        if (!isRevertingChanges && e.Column.ColumnName.Equals(TestColumn2))
        {
            if (!e.Row.Table.Columns.Contains(TestColumn2Backup))
                e.Row.Table.Columns.Add(TestColumn2Backup);

            e.Row[TestColumn2Backup] = e.Row[TestColumn2];
        }
    }
}
Comments