Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine who fired an event

Tags:

c#

events

Background:

In my winforms form, I have a Checked ListView and a "master" checkbox called checkBoxAll. The behaviour of the master is as follows:

  • If the master is checked or unchecked, all ListViewItems must change accordingly.

  • If the user unchecks a ListViewItem, the master must change accordingly.

  • If the user checks a ListViewItem, and all other ListViewItems are checked aswell, the master must change accordingly.

I have written the following code to mimic this behaviour:

private bool byProgram = false; //Flag to determine the caller of the code. True for program, false for user.

private void checkBoxAll_CheckedChanged(object sender, EventArgs e)
{
    //Check if the user raised this event.
     if (!byProgram)
     {
         //Event was raised by user!

         //If checkBoxAll is checked, all listviewitems must be checked too and vice versa.

         //Check if there are any items to (un)check.
         if (myListView.Items.Count > 0)
         {
             byProgram = true; //Raise flag.

             //(Un)check every item.
             foreach (ListViewItem lvi in myListView.Items)
             {
                 lvi.Checked = checkBoxAll.Checked;
             }

             byProgram = false; //Lower flag.
         }
     }
}

private void myListView_ItemChecked(object sender, ItemCheckedEventArgs e)
{
    //Get the appropiate ListView that raised this event
    var listView = sender as ListView;

    //Check if the user raised this event.
    if (!byProgram)
    {
        //Event was raised by user!

        //If all items are checked, set checkBoxAll checked, else: uncheck him!

        bool allChecked = true; //This boolean will be used to set the value of checkBoxAll

        //This event was raised by an ListViewItem so we don't have to check if any exist. 
        //Check all items untill one is not checked.
        foreach (ListViewItem lvi in listView.Items)
        {
            allChecked = lvi.Checked;
            if (!allChecked) break;
        }

        byProgram = true; //Raise flag.

        //Set the checkBoxAll according to the value determined for allChecked.
        checkBoxAll.Checked = allChecked;

        byProgram = false; //Lower flag.
    }
}

In this example, I use a flag (byProgram) to make sure an event was caused by the user or not, thereby preventing an infinite loop (one event can fire another, which can fire the first one again etc. etc.). IMHO, this is a hacky solution. I searched around but I couldn't find a MSDN documented method to determine if an User Control Event was directly fired thanks to the user. Which strikes me as odd (again, IMHO).

I know that the FormClosingEventArgs has a field which we can use to determine if the user is closing the form or not. But as far as I know, that is the only EventArg that provides this kind of functionality...

So in summary:

Is there a way (other than my example) to determine if an event was fired directly by the user?

Please note: I don't mean the sender of an event! It won't matter if I code someCheckBox.Checked = true; or manually set someCheckBox, the sender of the event will always be someCheckBox. I want to find out if it is possible to determine whether it was through the user (click) or by the program (.Checked = true).

Aaand also: 30% of the time it took to write this question was to formulate the question and the title correctly. Still not sure if it is a 100% clear so please edit if you think you can do better :)

like image 663
Jordy Avatar asked Jul 09 '13 11:07

Jordy


2 Answers

No, there's no practical way to determine whether the change came from GUI or was done by program (in fact, you could analyze the callstack - but that's not recommended because it's very slow and error-prone).

BTW, there's one other thing you could do instead of setting byProgram. You could remove and add the event handler prior or after, respectively, change your controls:

checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged;
// do something
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged;
like image 82
JeffRSon Avatar answered Sep 22 '22 14:09

JeffRSon


Instead of using the changed event, you could use the clicked event to cascade the change through to the relevant controls. This would be in response to a user click, and not the value being changed programatically.

like image 41
Tevo D Avatar answered Sep 23 '22 14:09

Tevo D