确定是谁解雇了一个事件

Jor*_*rdy 5 c# events

背景:

在我的winforms表单中,我有一个Checked ListView和一个名为checkBoxAll的"master"复选框.主人的行为如下:

  • 如果选中或取消选中主服务器,则所有ListViewItems必须相应地更改.

  • 如果用户取消选中ListViewItem,则主服务器必须相应地更改.

  • 如果用户检查了ListViewItem,并且还检查了所有其他ListViewItem,则主服务器必须相应地进行更改.

我编写了以下代码来模仿这种行为:

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.
    }
}
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我使用一个标志(byProgram)来确保一个事件是由用户引起的,从而防止了无限循环(一个事件可以触发另一个事件,它可以再次触发第一个事件等等).恕我直言,这是一个hacky解决方案.我四处搜索但是找不到MSDN记录的方法来确定是否由于用户而直接触发了用户控件事件.这让我觉得奇怪(再次,恕我直言).

我知道FormClosingEventArgs有一个字段,我们可以用它来确定用户是否正在关闭表单.但据我所知,这是唯一提供此类功能的EventArg ......

总结如下:

有没有办法(除了我的例子)确定一个事件是否是由用户直接触发的?

请注意:我不是指活动的发件人!如果我编写someCheckBox.Checked = true则无关紧要; 或者手动设置someCheckBox,事件的发送者将始终是someCheckBox.我想知道是否可以通过用户(点击)或程序(.Checked = true)来确定它是否可以.

Aaand还有:写这个问题花了30%的时间来正确地提出问题和标题.仍然不确定它是否100%清除所以请编辑,如果你认为你可以做得更好:)

Jef*_*Son 5

不,没有切实可行的方法来确定更改是来自GUI还是由程序完成(实际上,您可以分析调用堆栈 - 但不推荐这样做,因为它非常慢且容易出错).

顺便说一句,还有一件事你可以做而不是设定byProgram.您可以分别在更改控件之前或之后删除并添加事件处理程序:

checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged;
// do something
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged;
Run Code Online (Sandbox Code Playgroud)


Jam*_*mes 2

这是我经常遇到的事情,我倾向于尝试做的不是将其分为用户交互与程序交互 - 我使用更通用的代码,即 UI 正在更新并且不需要处理任何事件。我通常通过BeginUpdate/EndUpdate方法将其打包,例如

private int updates = 0;

public bool Updating { get { return updates > 0; } }

public void BeginUpdate()
{
    updates++;
}

public void EndUpdate()
{
    updates--;
}

public void IndividualCheckBoxChanged(...)
{
    if (!Updating)
    {
        // run code
    }
}

public void CheckAllChanged(...)
{
    BeginUpdate();
    try
    {
        // run code
    }
    finally
    {
        EndUpdate();
    }
}
Run Code Online (Sandbox Code Playgroud)