Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 防止调用下一个事件处理程序_C#_.net_Event Handling - Fatal编程技术网

C# 防止调用下一个事件处理程序

C# 防止调用下一个事件处理程序,c#,.net,event-handling,C#,.net,Event Handling,我有两个事件处理程序连接到Windows窗体中的按钮单击,如下所示: this.BtnCreate.Click += new System.EventHandler(new RdlcCreator().FirstHandler); this.BtnCreate.Click += new System.EventHandler(this.BtnCreate_Click); 两者都被正确调用 但是,在FirstHandler()中是否有可能阻止执行BtnCreate\u Click()?比如: v

我有两个事件处理程序连接到Windows窗体中的按钮单击,如下所示:

this.BtnCreate.Click += new System.EventHandler(new RdlcCreator().FirstHandler);
this.BtnCreate.Click += new System.EventHandler(this.BtnCreate_Click);
两者都被正确调用

但是,在
FirstHandler()
中是否有可能阻止执行
BtnCreate\u Click()
?比如:

void FirstHandler(object sender, EventArgs e)
{
   if (ConditionSatisfied)
     //Prevent next handler in sequence being executed

}
public static class CancellableEventChain
{
    public static EventHandler CreateFrom(params CancelEventHandler[] chain)
    {
        return (sender, dummy) =>
        {
            var args = new CancelEventArgs(false);
            foreach (var handler in chain)
            {
                handler(sender, args);
                if (args.Cancel)
                    break;
            }
        };
    }
}

我知道我可以取消订阅活动,但这可以通过编程方式(从方法内部)完成吗?

据我所知,没有解决方案。这是因为无法保证事件发生时调用事件处理程序的顺序


因此,您不应该以任何方式依赖它们的顺序。

在此添加以下条件。btn创建\u单击这是第二个事件

BtnCreate_Click(object sender, EventArgs e)  
{     
   if (!ConditionSatisfied)       //Prevent next handler in sequence being executed 
   {
     // your implementation goes here
   }   
}  

为什么不用一个eventhandler替换它们呢?大概是这样的:

var rdlc = new RdlcCreator();
this.BtnCreate.Click += (sender, e) => {
    rdlc.FirstHandler(sender, e);
    if (!rdlc.HasHandledStuff) { // <-- You would need some kind of flag 
        this.BtnCreate_Click(sender, e);
    }
};
编辑:或者,您只需将第二个处理程序传递给第一个处理程序。
将FirstHandler的签名更改为:

void FirstHandler(object sender, EventArgs e, EventHandler nextHandler) {
    if (ConditionSatisfied) {
        // do stuff
    }
    else if (nextHandler != null) {
        nextHandler(sender, e);
    }
}
然后:

this.BtnCreate.Click += 
    (s, e) => new RdlcCreator().Firsthandler(s, e, this.BtnCreate_Click);

我建议您创建一个类包装器。因此,您可以在那里存储某种类型的事件标志组(例如,16位整数)和一些设置或取消设置单个位的方法(其中每个方法都表示调用或不调用特定的
事件处理程序)。您可以轻松地将
事件处理程序的任何计数
甚至
操作
存储在类中,并按所需的任何顺序调用。

系统。ComponentModel
命名空间包含用于此目的的委托。它提供的参数之一是一个实例,该实例包含一个布尔
Cancel
属性,可以将该属性设置为任何处理程序,以指示调用列表的执行应该停止

但是,要将其附加到普通的
EventHandler
委托,您需要创建自己的包装器,例如:

void FirstHandler(object sender, EventArgs e)
{
   if (ConditionSatisfied)
     //Prevent next handler in sequence being executed

}
public static class CancellableEventChain
{
    public static EventHandler CreateFrom(params CancelEventHandler[] chain)
    {
        return (sender, dummy) =>
        {
            var args = new CancelEventArgs(false);
            foreach (var handler in chain)
            {
                handler(sender, args);
                if (args.Cancel)
                    break;
            }
        };
    }
}
对于您的示例,您可以这样使用它:

this.BtnCreate.Click += CancellableEventChain.CreateFrom(
    new RdlcCreator().FirstHandler,
    this.BtnCreate_Click
    /* ... */
);

当然,如果以后需要取消订阅(分离)创建的链处理程序,则需要在字段中捕获该处理程序。

正在寻找同一问题的解决方案,但运气不佳。所以我必须自己解决。 可取消事件参数的基类

public class CancelableEventArgs
{
    public bool Cancelled { get; set; }
    public void CancelFutherProcessing()
    {
        Cancelled = true;
    }
}
接下来定义EventHandler的扩展方法,注意调用列表订阅者是按向后顺序调用的(在我的例子中,UI元素可以是添加到组件中的事件,因此稍后呈现的元素具有最高的可视性和优先级)

因此,如果UI元素对事件有一些行为,它将取消进一步的处理

        game.OnMouseLeftButtonDown += (sender, a) =>
        {
            var xy = GetChessboardPositionByScreenPosition(a.XY);
            if (IsInside(xy))
            {
                var args = new ChessboardEventArgs { Position = xy };
                OnMouseDown.SafeInvokeWithCancel(this, args);
                a.CancelFutherProcessing();
            }
        };

为什么不使用布尔标志呢?ConditionSuccessed通过ChainEventArgs模拟oneReplace EventArgs,并向其中添加一些可以支持处理程序的变量。chain LogicHandler会按照附加的顺序调用,除非故意以奇怪的方式实现添加/删除访问器。为什么不给他们打电话?它们存储在一个简单的列表中。@Groo虽然所有处理程序都是按其附加的顺序调用的,但这是一个不应该依赖的实现细节。我同意,不能依赖顺序,我会找到另一个方法。实现细节?根据MSDN:。我希望看到一个具体的例子,其中有人覆盖了
add
访问器,并对列表进行了洗牌,以混淆他们的API用户。如果你真的想变得多疑,谁能保证我的访问者不会是这样:
add{}
?你没有理解我的意思,伙计。您正在CreateFrom EventHandler中使用此条件,但我已将其放在BtnCreate\u Click EventHandler中。不同之处在于,您不需要取消订阅活动。这是唯一正统的方法。
        game.OnMouseLeftButtonDown += (sender, a) =>
        {
            var xy = GetChessboardPositionByScreenPosition(a.XY);
            if (IsInside(xy))
            {
                var args = new ChessboardEventArgs { Position = xy };
                OnMouseDown.SafeInvokeWithCancel(this, args);
                a.CancelFutherProcessing();
            }
        };