背景
在我的winforms表单中,我有一个 Checked ListView 和一个名为 checkBoxAll 的“主”复选框。 主人的行为如下:
如果选中或取消选中主控,则所有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.
}
}
在这个例子中,我使用一个标志( byProgram )来确保事件是否由用户引起,从而防止了无限循环(一个事件可以触发另一个事件,这可以触发再来一次等等)。恕我直言,这是一个hacky解决方案。 我四处搜索但是找不到MSDN记录的方法来确定是否由于用户而直接触发了用户控件事件。这让我感到奇怪(再次,恕我直言)。
我知道FormClosingEventArgs有一个字段,我们可以用它来确定用户是否正在关闭表单。但据我所知,这是唯一提供此类功能的EventArg ......
总结如下:
有没有办法(除了我的例子)确定某个事件是否是由用户直接触发的?
请注意:我不是指活动的发件人!如果我编写someCheckBox.Checked = true则无关紧要;或者手动设置someCheckBox,事件的发送者将始终是someCheckBox。我想知道是否可以通过用户(点击)或程序(.Checked = true)来判断它。
Aaand还:写这个问题所花费的时间有30%是为了正确地制定问题和标题。仍然不确定它是否100%清除所以请编辑,如果你认为你可以做得更好:)
答案 0 :(得分:5)
不,没有切实可行的方法来确定更改是来自GUI还是由程序完成(实际上,您可以分析callstack - 但不建议这样做,因为它非常慢且容易出错)。
顺便说一句,你还可以做另外一件事,而不是设置byProgram
。您可以分别在更改控件之前或之后删除并添加事件处理程序:
checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged;
// do something
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged;
答案 1 :(得分:4)
您可以使用单击的事件将更改级联到相关控件,而不是使用已更改的事件。这将是对用户点击的响应,而不是以编程方式更改的值。
答案 2 :(得分: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();
}
}