Rawns
Rawns

Reputation: 875

Any easy way to alert to changes in multiple text boxes?

I'm fairly new to programming so sorry if this is simple, but I might just be missing the obvious! I have the following form which is automatically populated on load from settings stored in an INI file:

Configuration screen

The whole form is working just as I want it to apart form one small part. The 'Close' button currently just closes the form so that if any values have changed in the text boxes since the form was loaded, the changes are lost. I want to instead prompt the user to use the Save button instead otherwise the changes will be lost.

I've been trying to do something along these lines on my close button where the value of the text boxes are checked against the variable values that they were originally populated with:

private void btnClose_Click(object sender, EventArgs e)
{
    if (txtName.Text != name || txtSchName.Text != schname || txtServer1.Text != svr1 etc etc etc)
    {
       Warn User changes will be lost, ask user if really OK to close?
       if (User chooses to to close)
       {
            this.Close();
       }
       else
       {
            Go back to the config form;
       }    
    }
    else
    {
        this.Close();
    }

With over 21 text fields, I was not sure if this was the most "tidy way" of checking for changes? Any pointers would be appreciated.

Upvotes: 0

Views: 938

Answers (4)

Antonín Lejsek
Antonín Lejsek

Reputation: 6103

One disadvantage of dirtytracer is, that it returns "dirty" even when changes revert to original state. If You use object in DataContext as Your data model, all this task simplifies to:

bool changed = dataContext.SomeTables.GetModifiedMembers(someRow).Any(); 

Upvotes: 0

Rohit
Rohit

Reputation: 10236

What you are looking for is Dirty Tracking. Dirty tracking is used to track states of your control. Here is a simple reusable approach to track your controls

 public class SimpleDirtyTracker
 {

    private Form _frmTracked;  
    private bool _isDirty;


    public SimpleDirtyTracker(Form frm)
    {
      _frmTracked = frm;
       AssignHandlersForControlCollection(frm.Controls);
    }



     // property denoting whether the tracked form is clean or dirty
     public bool IsDirty
     {
       get { return _isDirty; }
       set { _isDirty = value; }
     }

      // methods to make dirty or clean
     public void SetAsDirty()
     {
       _isDirty = true;
     }


     public void SetAsClean()
     {
       _isDirty = false;
     }


     private void SimpleDirtyTracker_TextChanged(object sender, EventArgs e)
     {
      _isDirty = true;
     }

    private void SimpleDirtyTracker_CheckedChanged(object sender, EventArgs e)
   {
      _isDirty = true;
   }

     // recursive routine to inspect each control and assign handlers accordingly
   private void AssignHandlersForControlCollection(
   Control.ControlCollection coll)
   {
     foreach (Control c in coll)
    {
      if (c is TextBox)
          (c as TextBox).TextChanged 
            += new EventHandler(SimpleDirtyTracker_TextChanged);

      if (c is CheckBox)
          (c as CheckBox).CheckedChanged 
            += new EventHandler(SimpleDirtyTracker_CheckedChanged);

      // ... apply for other desired input types similarly ...

      // recurively apply to inner collections
      if (c.HasChildren)
          AssignHandlersForControlCollection(c.Controls);
  }
}

and in your mainform

  public partial class Form1 : Form
  {

    private SimpleDirtyTracker _dirtyTracker;



    private void Form1_Load(object sender, EventArgs e)
    {

      _dirtyTracker = new SimpleDirtyTracker(this);
      _dirtyTracker.SetAsClean();
    }

   private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
    // upon closing, check if the form is dirty; if so, prompt
    // to save changes
    if (_dirtyTracker.IsDirty)
    {
        DialogResult result
            = (MessageBox.Show(
                "Would you like to save changes before closing?"
                , "Save Changes"
                , MessageBoxButtons.YesNoCancel
                , MessageBoxIcon.Question));

     }

}

Upvotes: 4

daniel59
daniel59

Reputation: 916

If you want to save for example usersettings you could create Settings in your Properties.

You can get them like this:

string anyProperty = WindowsFormsApplication1.Properties.Settings.Default.TestSetting;

You save them using the Save-method:

WindowsFormsApplication1.Properties.Settings.Default.TestSetting = "Hello World";
WindowsFormsApplication1.Properties.Settings.Default.Save();

You can call the Save-method after you have clicked the close-button.

For saving several string properties you could create a property of the type System.Collections.Specialized.StringCollection, so that you just create one property and not 21.

Upvotes: 0

Steve
Steve

Reputation: 216293

You just add a global boolean variable and write an handler for the TextChanged event

// Declared at the form level
private bool _modified = false;

public Form1()
{
    InitializeComponent();

    // This could be done in the form designer of course 
    // o repeated here for every textbox involved....
    txtName.TextChanged += OnBoxesChanged;
    ......
}
private void Form1_Load(object sender, EventArgs e)
{
     .....
     // Code that initializes the textboxes could raise the TextChanged event
     // So it is better to reset the global variable to an untouched state
     _modified = false;
}
private void OnBoxesChanged(object sender, EventArgs e)
{
    // Every textbox will call this event handler
    _modified = true;
}
private void btnClose_Click(object sender, EventArgs e)
{
    if(_modified)
    {
         // Save, warning, whatever in case of changes  ....
    }

}

Just set the event handler OnBoxesChanged for every textbox you want to trigger the condition. You could do it through the Designer or manually after the InitializeComponent call

Upvotes: 4

Related Questions