代码之家  ›  专栏  ›  技术社区  ›  MatthewMartin muthu

如何在C#中以特定顺序处理事件?

  •  0
  • MatthewMartin muthu  · 技术社区  · 15 年前

    编辑:我是否忽略了一个更简单的设计,它不需要向应用程序中的每个编辑/保存/更新按钮句柄添加锅炉板代码?那么,一个项目负责人与另一个项目负责人沟通的正确方式是什么?例如,基页需要传达成功或失败验证,派生类需要传达保存的成功或失败,以便可以在审核中记录。

    //Base page-- seems like this will work if events happen in order of wireup.
    protected override void OnInit(EventArgs e)
    {
        foreach (Control possibleButton in Controls)
        {
            if(possibleButton is Button)
            {
                Button button = (Button) possibleButton;
                button.Command += ButtonCommandPreconditions;
            }
        }
        base.OnInit(e);
        foreach (Control possibleButton in Controls)
        {
            if(possibleButton is Button)
            {
                Button button = (Button) possibleButton;
                button.Command += ButtonCommandPostconditions;
            }
        }
    }
    
    void ButtonCommandPreconditions(object sender, CommandEventArgs e)
    {
            if(e.CommandName=="Save" || e.CommandName=="Edit")
            {
                //Stuff that needs to happen before other handler   
                //Validate, display failures-- maybe set IsValdated property
                //Check for POST/GET, throw exception on GET.
                //Check for ID, throw exception on anonymous user
                //Check for authorization
                //Display authorization failures-- maybe set IsAuthorized property 
            }
    }
    
    void ButtonCommandPostconditions(object sender, CommandEventArgs e)
    {
            if(e.CommandName=="Save" || e.CommandName=="Edit")
            {
                 //Stuff that needs to happen *after* other handler
                //Log save
            }
    }
    

    编辑: 修改了代码,以反映事件处理者应该按连线顺序处理。

    3 回复  |  直到 15 年前
        1
  •  5
  •   Community CDub    7 年前

    事件只是多播委托,因此事件处理程序将按照添加到事件中的顺序引发。

    更好的做法是将事件冒泡到父处理程序中,以便在进行自己的处理之前从每个继承的页面进行处理。这样就有了明确的联系,代码很容易理解,而且您不必依赖于关于事件顺序的假设。


    编辑新问题:

    对一个人来说,正确的方法是什么 要与之通信的事件处理程序 另一个

    你应该看看我的答案 this post.

    例如,基本页面需要 沟通成功或失败 沟通项目的成功或失败 审计

    有很多方法可以解决这个问题。首先,只需让基类调用可以在派生页中重写的抽象或虚拟方法。在基本页中的按钮单击处理程序中,执行所有验证,然后调用派生页的抽象“DoSave()”方法,并进行检查以确保其成功。

    derived classes raise the event


    我想补充一点,似乎您正在将大量内容加载到基类按钮中。当页面呈现时,您是否可以执行匿名ID和GET/POST检查,如果按钮没有权限,则不呈现按钮?

        2
  •  3
  •   Alex K    15 年前

    虽然我不准备提供解决方案(因为这需要更多地了解您的设计),但除了告诉您将“保存”(和类似事件)逻辑分离到它们自己的类层次结构中,并在一次生命中从事件处理程序调用它们之外。但是,我可以对您的原始问题进行评论(在您以粗体编辑之前)。设置的问题是,虽然您可以按特定顺序引发事件,但任何.Net Framework中的事件都不能保证按交付顺序进行。当您在dev机器上进行测试时,这些事件可能看起来是有序的,但在实际部署中,当系统负载变高时,这些事件将首先被推迟,以便进行其他操作。事件 到达 对他们的听众来说,基本上是随机的。

    您不应该根据接收事件的顺序构建逻辑。每个事件必须只考虑当前状态,不能假设任何其他事件。当你最需要的时候,你的事件链就会断开。

        3
  •  1
  •   Ben M    15 年前

    class BaseClass
    {
        public event CommandEventHandler ButtonCommand = delegate { };
    
        protected override void OnInit(EventArgs e)
        {
            foreach (Control possibleButton in Controls)
            {
                if (possibleButton is Button)
                {
                    Button button = (Button) possibleButton;
                    button.Command += AnyButtonCommandHandler;
                }
            }
            base.OnInit(e);
        }
    
        void AnyButtonCommandHandler(object sender, CommandEventArgs e)
        {
            // validation logic. if fails, return.
    
            ButtonCommand(sender, e);
        }
    }
    
    class DerivedClass : BaseClass
    {
        public DerivedClass()
        {
            base.ButtonCommand += base_ButtonCommand;
        }
    
        void base_ButtonCommand(object sender, CommandEventArgs e)
        {
            if (sender == button1) { ... }
            else if (sender == button2) { ... }
            // etc.
        }
    }
    

    你也可以考虑更换 ButtonCommand protected void OnButtonCommand(object sender, CommandEventArgs e) (或两者兼而有之);然后,您可以简单地覆盖 OnButtonCommand 在派生类中。