现在的位置: 首页 > 综合 > 正文

类似SCSF中EventBroker解耦事件调用方和接受方,打破”+=”带来的耦合

2018年05月27日 ⁄ 综合 ⁄ 共 3486字 ⁄ 字号 评论关闭

今天在网上闲逛,偶然发现一个老外的开源组件,里面实现了微软SCSF框架中的EventBroker模块的功能,它的使用和SCSF几乎一样,熟悉SCSF的人几乎一下就能上手,只是这个类库不再像SCSF一样,只能在框架中使用,它不依赖于SCSF,可以用在WinForm,WPF中,是一个独立的组件

原本应该在"Code Project"上可以下载的,上面只有它的介绍,下载链接好像有问题

http://www.codeproject.com/Articles/30066/EventBroker-a-notification-component-for-synchrono

我在百度上找了很久,终于找到一个可以下载的地方,这里是它的源码。

http://sourceforge.net/projects/bbvcommon/

我之所以青睐这个库,是因为它用C#的Attribute解耦了事件注册时由"+="带来的调用方与接收方的依赖(当然解耦的方式有很多,但我觉得这个方式最优雅)

下面就是一个事件发布类,它采用了Attribute来标记,其中的"topic://EventBrokerSample/SimpleEvent"为事件的Uri,是他的唯一标示。

public class Publisher
{
    [EventPublication("topic://EventBrokerSample/SimpleEvent")]
    public event EventHandler SimpleEvent;
    
    ///<summary>Fires the SimpleEvent</summary>
    public void CallSimpleEvent()
    {
        SimpleEvent(this, EventArgs.Empty);
    }
}

下面是事件的订阅部分,同样是用Attribute来标记,采用同样的Uri来标示为上面事件的接收

public class Subscriber
{
    [EventSubscription(
        "topic://EventBrokerSample/SimpleEvent", 
        typeof(Handlers.Publisher))]
    public void SimpleEvent(object sender, EventArgs e)
    {
        // do something useful or at least funny
    }
}

最后,包含事件订阅的对象需要EventBroker来注册,这个相当与"+=",只是它可以完全不关注事件的发布者是谁(这和SCSF的方式一模一样),它使用的是反射Attribute元数据的方式,然后调用DynamicInvoke方法调用委托

下面是我使用该组件的一个例子

窗体上下,各自放了一个UserControl,首先他们加载的时候,接受了窗体Form1触发的事件,然后点击UserControl1的按钮改变UserControl2的文本框文本,反之UserControl2亦然,我用单例模式把EventBroker对象管理了起来,不然使用起来太不方便了

    public class EventBrokerCreator
    {
        private static EventBroker _instance = null;
        private EventBrokerCreator()
        {}

        public static EventBroker GetEventBroker()
        {
            return _instance ?? (_instance = new EventBroker());
        }
    }

下面是两个用户控件,他们各自定义了事件的发布和订阅

    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        [EventPublication(EventTopics.UserCtrol1)]
        public event EventHandler UserCtrol1Event;

        private void button1_Click(object sender, EventArgs e)
        {
            if (UserCtrol1Event != null)
                UserCtrol1Event(this, EventArgs.Empty);
        }

        [EventSubscription(EventTopics.UserCtrol2, typeof(Publisher))]
        public void UserCtrol1Send(object sender, EventArgs e)
        {
            textBox1.Text = "UserControl2 Send";
        }

        [EventSubscription(EventTopics.Form1, typeof(Publisher))]
        public void Form11Send(object sender, EventArgs e)
        {
            textBox1.Text = "Form1 Send";
        }
    }

    public partial class UserControl2 : UserControl
    {
        public UserControl2()
        {
            InitializeComponent();
        }

        [EventPublication(EventTopics.UserCtrol2)]
        public event EventHandler UserCtrol2Event;

        private void button1_Click(object sender, EventArgs e)
        {
            if (UserCtrol2Event != null)
                UserCtrol2Event(this, EventArgs.Empty);
        }

        [EventSubscription(EventTopics.UserCtrol1, typeof(Publisher))]
        public void UserCtrol1Send(object sender, EventArgs e)
        {
            textBox1.Text = "UserControl1 Send";
        }

        [EventSubscription(EventTopics.Form1, typeof(Publisher))]
        public void Form11Send(object sender, EventArgs e)
        {
            textBox1.Text = "Form1 Send";
        }
    }

在Form1中发布一个事件,两个用户控件来订阅

    public partial class Form1 : Form
    {
        public Form1()
        {
            //为了方便说明,用户控件的实例化部分从Designer.cs中移到这里
            this.userControl1 = new Sample.UserControl1();
            this.userControl2 = new Sample.UserControl2();
            //注册事件订阅对象
            var eventBroker = EventBrokerCreator.GetEventBroker();
            eventBroker.Register(userControl1);
            eventBroker.Register(userControl2);
            InitializeComponent();
        }

        [EventPublication(EventTopics.Form1)]
        public event EventHandler Form1Event;

        private void Form1_Load(object sender, EventArgs e)
        {
            if (Form1Event != null)
                Form1Event(this, EventArgs.Empty);
        }
    }

最后还需要在Program.cs中对Form1进行EventBroker的注册

        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            //由于是单例模式,所有的EventBroker对象都是同一个
            var eventBroker = EventBrokerCreator.GetEventBroker();
            var form1 = new Form1();
            eventBroker.Register(form1);

            Application.Run(form1);
        }

好了,大功告成了,有兴趣的人可以自己写个demo玩一下,个人觉得 eventBroker.Register(form1);这种注册的方式不够优雅,还有改进的余地。

我文中的源码这里可以下载

点击下载



抱歉!评论已关闭.