3

I have a bunch of controls on a form and all of their "change" events point to the same event handler. Some of these are txtInput1's TextChanged, chkOption1's CheckedChanged, and cmbStuff1's SelectedIndexChanged. Here is the event handler:

private void UpdatePreview(object sender, EventArgs e)
{
    // TODO: Only proceed if event was fired due to a user's clicking/typing, not a programmatical set
    if (sender.IsSomethingThatTheUserDid) // .IsSomethingThatTheUserDid doesn't work
    {
        txtPreview.Text = "The user has changed one of the options!";
    }
}

I would like the if statement to only run when a user changes the TextBox text or clicks a checkbox or whatever. I don't want it to happen if the text or checkbox was changed by some other part of the program.

Coder7862396
  • 415
  • 1
  • 6
  • 13
  • I could swear I just answered a question exactly like this recently... – lc. Jun 23 '10 at 17:21
  • 1
    Here it is. It's not exactly a complete duplicate, but the answer is still the same: http://stackoverflow.com/questions/3071811/listbox-selectedindexchanged-can-you-determine-if-it-was-user-intiated/3071856 – lc. Jun 23 '10 at 17:23
  • Can you clarify what you mean when you state "I don't want it to happen if the text or checkbox was changed by some other part of the program." – Doug Jun 23 '10 at 17:24
  • One thing I want to add is this will work if you want to prevent the event code from running. But this will not save you from performance issues if your event gets called many and possibly hundreds of times. You will need to look into unhooking and suppressing events. – Bryan Harrington Apr 17 '19 at 16:10

2 Answers2

11

There isn't a built-in mechanism to do this. You can, however, use a flag.

bool updatingUI = false;

private void UpdatePreview(object sender, EventArgs e)
{
    if (updatingUI) return;

    txtPreview.Text = "The user has changed one of the options!";
}

Then, when you're updating the UI from your code:

updatingUI = true;

checkBox1.Checked = true;

updatingUI = false;

If you want to over-engineer the solution, you could use something like this:

private void UpdateUI(Action action)
{
    updatingUI = true;

    action();

    updatingUI = false;
}

And use it like this:

UpdateUI(()=>
{
    checkBox1.Checked = true;
});
Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
  • Thanks, I was just assuming that there was a built-in mechanism to do this. I'll use a flag. Plus I learned something new with the syntax in your last code block :) – Coder7862396 Jun 23 '10 at 17:43
  • @Coder: It's called a lambda expression. You should find plenty of information about them. Good luck! – Adam Robinson Jun 23 '10 at 17:57
0

Can't you just check the sender? If it's called from a wired event to a UI control, it will come back with the control. If you're firing the event from code, it will either be the component making the call, or you could make it anything you want:

private void SomewhereElse()
{
   UpdatePreview(null, new EventArgs());
}

private void UpdatePreview(object sender, EventArgs e)
{
    if (sender == null) 
    {
        txtPreview.Text = "The user has changed one of the options!";
    }
}

or you may be able to do this:

private void UpdatePreview(object sender, EventArgs e)
{
    if (!(sender is Control)) 
    {
        txtPreview.Text = "The user has changed one of the options!";
    }
}
Robaticus
  • 22,857
  • 5
  • 54
  • 63
  • This is incorrect. The sender is always the object raising the event. Regardless of whether the `Text` property was changed by input or by code, the `sender` variable will always be the instance of the textbox that raised the event. – Adam Robinson Jun 23 '10 at 17:40
  • It's not "UpdatePreview()" that is being called from somewhere else, it's the setting of the text or checkbox (txtInput1.Text = "Hello from somewhere else") – Coder7862396 Jun 23 '10 at 17:43
  • @Adam - This is incorrect from the standpoint of answering the posted question. I had misread what he was trying to do. My answer is correct within the context that I posted. @Coder7862396 - You're absolutely right. I missed that in the original posting. – Robaticus Jun 23 '10 at 21:42
  • I understand what you're getting at, but you said "firing the event from code". Calling the event handler is not the same thing as firing the event; the only way to fire the event is to do something to the control to get it to fire the event, which means that the answer is incorrect (`sender` will always refer to the sending control when the event is fired/invoked, regardless of source). – Adam Robinson Jun 24 '10 at 01:11