Question Implement Undo button on bound textbox

Glenn

Member
Joined
Mar 12, 2021
Messages
6
Programming Experience
10+
I normally manually populate my forms fields and handle everything from there owing to years ago giving up owing to all the practical problems with bound Winform controls in all but the simplest scenarios. Thought I'd give it another shot.

I have a grid populated with a datatable (not connected to a dataset) and fields bound to the same datatable. When the user selects a grid record, the below fields are populated with the record and edited. I want an Undo button that they can change edits to the current record but everything I try does not clear the textbox, and even the underlying table unless it is already dirty. Here is how I am handling:

binding a textbox (_dtUsers is a datatable):

C#:
txtFirstName.DataBindings.Add(new Binding("Text", _dtUsers, "UFNm"));

Here is how I am trying to undo (note "CurrentRow" is a property I capture on ColumnChangeing or RowChanged events)

C#:
{
    try
    {
        txtUserID.Focus();   //to force a field move

        if (!CurrentRow.IsNull())
        {
            CurrentRow.RejectChanges();
        }
    }
    catch (Exception ex)
    {
        _mainform.HandleException(ex);
    }
}

The major problem: before changing records, the datatable doesn't know the row has been changed and RejectChanges does nothingto the current row. After the table is dirty, it will clear the current row but the text box will not reflect the change unless I go to another row and return.

So here's what I want:, if possible:
On a textbox (or other bound control) change--which does fire the Column and Row changed evenets of thte bound table-- I want to set the table to "Dirty", that is that it knows the row has been edited before moving on to another record. Then when I RejectChanges(), the record will revert to previous value and the textbox will also reflect it..

Thanks.
 
Last edited by a moderator:
I've never been in your before situation since the old WinForms UI I used to work on never had that condition of duplicated UI values in a data grid or some other container, and a details or child view with editable values on the same screen. (Thank God for some good UI designers I worked with!) I guess in your situation, I would have tried the same thing you did above. It seems like that approach doesn't work, so it maybe time to take it the big hammer solution: take a snapshot of the row values when the row is entered. If the user hits the Undo shortcut or menu item, then just drop in the snapshot values back into the appropriate places and let the binding propagate to the bound controls.

I hope someone can offer a better solution than that big hammer approach.
 
Bind your DataTable to a BindingSource and then bind that to your controls. To undo changes made to the current record, call CancelEdit on the BindingSource. E.g.
C#:
private void Form1_Load(object sender, System.EventArgs e)
{
    var table = new DataTable();

    table.Columns.Add("PersonId", typeof(int));
    table.Columns.Add("GivenName", typeof(string));
    table.Columns.Add("FamilyName", typeof(string));

    table.Rows.Add(1, "Peter", "Smith");
    table.Rows.Add(2, "Paul", "Jones");
    table.Rows.Add(3, "Mary", "Williams");

    bindingSource1.DataSource = table;
    dataGridView1.DataSource = bindingSource1;
    textBox1.DataBindings.Add("Text", bindingSource1, "GivenName");
    textBox2.DataBindings.Add("Text", bindingSource1, "FamilyName");
}

private void button1_Click(object sender, System.EventArgs e)
{
    bindingSource1.CancelEdit();
}
 
Bind your DataTable to a BindingSource and then bind that to your controls. To undo changes made to the current record, call CancelEdit on the BindingSource. E.g.
C#:
private void Form1_Load(object sender, System.EventArgs e)
{
    var table = new DataTable();

    table.Columns.Add("PersonId", typeof(int));
    table.Columns.Add("GivenName", typeof(string));
    table.Columns.Add("FamilyName", typeof(string));

    table.Rows.Add(1, "Peter", "Smith");
    table.Rows.Add(2, "Paul", "Jones");
    table.Rows.Add(3, "Mary", "Williams");

    bindingSource1.DataSource = table;
    dataGridView1.DataSource = bindingSource1;
    textBox1.DataBindings.Add("Text", bindingSource1, "GivenName");
    textBox2.DataBindings.Add("Text", bindingSource1, "FamilyName");
}

private void button1_Click(object sender, System.EventArgs e)
{
    bindingSource1.CancelEdit();
}
OK, thanks. Looks good and what I am looking for.
 
Back
Top Bottom