屏蔽UI事件的最佳方法是什么?

时间:2013-02-18 14:04:11

标签: c# winforms events user-interface

我正在使用DataGridView,并使用CellValueChanged事件。

当我通过代码更改单元格值时,我不希望触发此事件。但是,我希望在用户编辑它时触发它。

这就是我使用以下代码附上我的单元格值更改操作的原因:

void changeCellOperation()
{
    dgv.CellValueChanged -= new DataGridViewCellEventHandler(dgv_CellValueChanged);

    ...
    cell.Value = myNewCellValue
    ...

    dgv.CellValueChanged += new DataGridViewCellEventHandler(dgv_CellValueChanged);
}

我结束了几个不同的函数,我的DataGridView单元格以这种方式更新。

因为这些函数是从不同的地方调用的并且可以嵌套,所以我不能保留这些代码,以避免事件不需要的事件重新激活。

所以我这样结束了:

int valueChangedEventMask = 0;

void changeCellOperation()
{
    valueChangedEventMask++;

    ...
    cell.Value = myNewCellValue
    ...

    valueChangedEventMask--;
}

void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
    if (valueChangedEventMask > 0)
        return

    ...
}

这很好用。此外,当嵌套调用时,包括事件本身内部。

CellValueChanged事件现在无理由地激发了太多次

因为我经常需要处理这种模式,所以我正在寻找一种适用于UI中事件的解决方案,而不仅仅是DataGridView。

所以我的问题是:

正确掩盖UI事件并避免不必要的事件触发的最佳提示是什么?

3 个答案:

答案 0 :(得分:0)

CellValueChanged不是UI事件,而是属性更改事件。这意味着您无法使用它来区分用户输入和程序化更改。你总是可以使用subscriber / unsucscribe或flag +/-或BeginEdit / EndEdit类似的技术,但也许你必须找到另一种(更好的)方法。例如,如果是复选框,您可以使用Click事件而不是Changed,因为(惊喜!)它会告诉您用户何时单击它,否则以编程方式安全地更改Checked的值

如果DataGridView最简单,可以使用带有标记的Changed(在编辑开始时设置,在结束时重置 - 请参阅CellBeginEdit/CellEndEdit)。

答案 1 :(得分:0)

您可以使用CellEndEdit代替CellValueChange。我不知道你的方法dgv_CellValueChanged做了什么,只要注意每次退出单元格的编辑模式时都会触发CellEndEdit,即使它的值没有被更改。这意味着如果您不希望在值没有更改时执行该方法,则必须跟踪单元格的当前值。

我会避免与鼠标相关的事件,例如CellClick,因为您的用户只能使用键盘。

无论如何,我通常通过将逻辑与用户界面分开来避免这种问题,即我写了一个绑定到表单的单独的类。看一下MVVM(你可以在WinForms中实现自己的版本,如果你想要的话)或好的MVC

答案 2 :(得分:0)

我最终将这两种解决方案混合在一起非常简单。我使用了一个计数器,我只挂钩/取消挂钩我要屏蔽的事件。

EventMask valueChangedEventMask;

// In the class constructor
valueChangedEventMask = new EventMask(
    () => { dgv.CellValueChanged += new DataGridViewCellEventHandler(dgv_CellValueChanged); },
    () => { dgv.CellValueChanged -= new DataGridViewCellEventHandler(dgv_CellValueChanged); }
);

// The value change operation I want to hide from the event
void changeCellOperation()
{
    valueChangedEventMask.Push();

    ...
    cell.Value = myNewCellValue
    ...

    valueChangedEventMask.Pop();
}

// The class
public class EventMask
{
    Action hook;
    Action unHook;

    int count = 0;

    public EventMask(Action hook, Action unHook)
    {
        this.hook = hook;
        this.unHook = unHook;
    }

    public void Push()
    {
        count++;
        if (count == 1)
            unHook();
    }

    public void Pop()
    {
        count--;
        if (count == 0)
            hook();
    }
}