【问题标题】:How to create a static global event so that one form can listen to another form's event that isn't a parent form?如何创建一个静态全局事件,以便一个表单可以监听另一个表单的不是父表单的事件?
【发布时间】:2019-08-23 10:48:07
【问题描述】:

我正在使用 WinForms,我有 3 个表单。 A 型、B 型和 C 型。

FormA 创建 FormB,FormB 创建 FormC。

我需要 FormA 知道 FormC 何时关闭。 FormB 没有参与。 我还有一个全局静态类,每个表单都可以访问。

我查看了How to properly listen form events with another formPropagating events from one Form to another Form in C#,但它们只适用于听FormC 的FormB。

如何在全局静态类中创建事件,以便 FormA 可以监听 FormC?

谢谢

【问题讨论】:

    标签: c# events static


    【解决方案1】:

    避免static 类和全局引用几乎总是100% 好。

    最好传递一个Action<FormC>,以便通知您FormC 正在关闭。

    试试这个:

    FormA

    public partial class FormA : Form
    {
        public FormA()
        {
            InitializeComponent();
        }
    
        private void Button1_Click(object sender, EventArgs e)
        {
            var formB = new FormB(this.ClosingC);
            formB.Show();
        }
    
        private void ClosingC(FormC formC)
        {
            MessageBox.Show("Closing C");
        }
    }
    

    FormB

    public partial class FormB : Form
    {
        public FormB()
        {
            InitializeComponent();
        }
    
        private Action<FormC> _closingFormC = null;
    
        public FormB(Action<FormC> closingFormC)
            : this()
        {
            _closingFormC = closingFormC;
        }
    
        private void Button1_Click(object sender, EventArgs e)
        {
            var formC = new FormC(_closingFormC);
            formC.Show();
        }
    }
    

    FormC

    public partial class FormC : Form
    {
        public FormC()
        {
            InitializeComponent();
        }
    
        private Action<FormC> _closingFormC = null;
    
        public FormC(Action<FormC> closingFormC)
            : this()
        {
            _closingFormC = closingFormC;
        }
    
        private void FormC_FormClosing(object sender, FormClosingEventArgs e)
        {
            _closingFormC?.Invoke(this);
        }
    }
    

    【讨论】:

    • 为什么使用静态类和全局引用是个坏主意?我认为这是一个好主意,因为除了创建 FormC 之外,FormB 不做任何其他事情,并且用户可以创建 FormB 的其他实例,而不必等到 FormC 完成关闭并提醒 FormA。
    • @csharpnewbie - 最终你会遇到这样一种情况,你想要打开多个FormA 实例,你需要知道哪个启动了A -&gt; B -&gt; C 链。静态引用将不起作用。
    • @csharpnewbie - 你也不能对静态类进行单元测试 - 这会使你的代码变得脆弱。
    • @csharpnewbie - 使用我的代码,您可以扩充Action&lt;FormC&gt; 以进行日志记录或测试等。FormB 中的代码可以这样写,例如:var formC = new FormC(c =&gt; { MessageBox.Show("Calling A now from B When Closing C"); _closingFormC(c); });static 课程不好的原因有很多。
    • 事件比动作更可取,因为它们允许多个订阅者。 FormB 最好公开一个事件 FormC_Closed。然后FormA可以订阅FormB.FormC_Closed事件,FormB可以订阅FormC.FormClosed事件。
    【解决方案2】:

    这是带有静态事件FormClosed的全局静态类:

    public static class GlobalStaticClass
    {
        public static event FormClosedEventHandler FormClosed;
        public static void OnFormClosed(object sender, FormClosedEventArgs e)
        {
            FormClosed?.Invoke(sender, e);
        }
    }
    

    这是FormC。引发FormClosed 事件:

    public partial class FormC : Form
    {
        public FormC()
        {
            InitializeComponent();
            this.FormClosed += (sender, e) =>
            {
                GlobalStaticClass.OnFormClosed(sender, e);
            };
        }
    }
    

    这是FormA 监听这个事件:

    public partial class FormA : Form
    {
        public FormA()
        {
            InitializeComponent();
            GlobalStaticClass.FormClosed += (sender, e) =>
            {
                //if (sender is FormC)
                MessageBox.Show(((Form)sender).Name + " Closed, reason: " + e.CloseReason);
            };
        }
    }
    

    【讨论】:

    • FormA 部分有问题,因为 FormA 不知道 FormC,因此无法调用 FormC.instanceClosed。
    【解决方案3】:

    我会使用事件聚合。这里是小号Install-Package Caliburn.Micro.EventAggregator

    习惯了

    public class MyForm : Form, IHandle<MyEvent>
    {
       public MyForm() 
       {
          SomeStaticPlace.EventAggregator.Subscribe(this); //Can be replaced with DI
       }
    
       public void Handle(MyEvent message) 
       {
          //Act on event
       }
    }
    

    并发布SomeStaticPlace.EventAggregator.Publish(new MyEvent(...));

    【讨论】:

    • 这个是在FormC中使用并发布到全局静态类然后FormA订阅的吗?
    • MyForm 上面是监听器。您可以从任何地方发布以调用它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 2011-08-06
    相关资源
    最近更新 更多