更改事件的顺序

本文关键字:顺序 事件 | 更新日期: 2023-09-27 18:32:00

我有一个控件(按钮),其中包含一个包含文本"Test A"的消息框,并添加了一个带有另一条消息"Test B"的委托。下面的代码首先显示消息"测试 A",然后显示"测试 B":

c.Click += delegate(object sender, EventArgs e)
{
    MessageBox.Show("Test B");        
};

我需要类似于我所做的代码的东西,但无法正常工作:

EventHandler handler;
c.click -= handler;
handler = delegate(Object sender, EventArgs e)
{
     MessageBox.Show("Test B");
};
c.Click += handler;

我需要更改顺序,即显示消息"测试 B",然后显示"测试 A"。可能吗?

更改事件的顺序

您可以取消注册并重新注册:

button1.Click -= button1_Click; // unregister main event
            button1.Click += delegate(object sender, EventArgs e) // reigster new one
            {
                MessageBox.Show("Test B");
            };
            button1.Click += button1_Click; // register again old

按钮单击事件:

private void button1_Click(object sender, EventArgs e)
{
   MessageBox.Show("Test A");
}

现在它将首先调用调用测试 B,然后调用测试 A

您提到您的程序包含某种编译器,并且用户可以指定其代码是在现有代码之前还是之后运行。在我看来,您可以简单地在您自己的事件处理程序中处理用户代码,该处理程序按所需的顺序运行您和用户的代码(正如 Nikola 已经提到的)。

换句话说,不要直接向用户代码公开这些事件,而是使用您自己的事件处理程序"包装"它们。从用户的角度来看,没有任何变化 - 他们仍然认为他们可以直接访问事件。但是您可以控制如何处理用户代码,因此您可以自由地在两者之间插入一个层,以确保正确的执行顺序:

c.Click += (sender, e) =>
{
    if (hasUserEventHandler && runUserEventHandlerFirst)
        UserEventHandler(sender, e);
    StandardEventHandler(sender, e);
    if (hasUserEventHandler && !runUserEventHandlerFirst)
        UserEventHandler(sender, e);
};

我的意思是,你可以做这样的事情:

public void SwapDelegateOrder(object obj, string eventName)
{
    // Fetch the underlying event handler field (let's *assume* it has the same name):
    var delegateField = obj.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    var mcDelegate = delegateField.GetValue(obj) as MulticastDelegate;
    if (mcDelegate == null)
        return;
    // Get the add and remove methods:
    var evt = obj.GetType().GetEvent(eventName);
    var add = evt.GetAddMethod(true);
    var remove = evt.GetRemoveMethod(true);
    // Remove all invocations...
    var invocations = mcDelegate.GetInvocationList();
    foreach (var invocation in invocations)
        remove.Invoke(obj, new object[] { invocation });
    // ...and add them back in, in reverse order (*assuming* that invocations are called in the order they're added):
    foreach (var invocation in invocations.Reverse())
        add.Invoke(obj, new object[] { invocation });
}

但这是基于有关编译器和运行时实现(事件字段名称和执行顺序)的假设。如果在编译器更新或下一个 .NET 框架版本中更改了其中一些详细信息,该怎么办?你无法控制它,但你可以控制自己的代码。