zoukankan      html  css  js  c++  java
  • 观察者模式的应用:Winform窗体之间传值

    观察者模式的应用:Winform窗体传值

    观察者模式的概念:

    定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并更新。

    今天我们就学着用一下这个观察者模式,先想象下这个场景:当一个窗体(主窗体)内的值发生变化时,另外几个窗体内的值也会发生相应的变化。这个最简单的实现方式是,在子窗体类内创建一个公共方法,在主窗体内创建子窗体的实例。当值发生变化时调用子窗体的公共方法。还有一种简单方法是用静态属性,相当于全局变量,这个只能针对小型应用。第一种有一个缺点,当增加子窗体时,我们需要更改主窗体类的代码。无法实现动态地增加删除对子窗体类中值的更新。这时可以引入观察者模式。
    我们先创建一个winform项目,添加FrmMain,FrmSub1,FrmSub2三个窗体,每个窗体都添加一个textbox文本框,实现当主窗体中的文本框值发生变化时,其他两个子窗体的值也会发生相应的变化。这里我们参考《Head First设计模式》,先设计发布者和订阅者(这里我感觉还是叫比较顺口)。代码如下:

     public interface ISubject
     {
         /// <summary>
         /// 注册订阅者
         /// </summary>
         /// <param name="observer"></param>
         void RegisterObserver(IObserver observer);
    
         /// <summary>
         /// 删除订阅者
         /// </summary>
         /// <param name="observer"></param>
         void RemoveObserver(IObserver observer);
    
         /// <summary>
         /// 通知订阅者
         /// </summary>
         void NotifyObservers();
     }
    
    public interface IObserver
    {
        /// <summary>
        /// 观察者对发布者的响应方法
        /// </summary>
        /// <param name="message"></param>
        void Update(string message);
    }
    

    修改FrmMain类,使其实现ISubject接口,再给文本框增加change事件,代码如下:

    public partial class FrmMain : Form, ISubject
    {
        private string Message { get; set; }
        private List<IObserver> _observers = new List<IObserver>();
    
    
        public FrmMain()
        {
            InitializeComponent();
        }
    
    
        private void FrmMain_Load(object sender, EventArgs e)
        {
            FrmSub1 frmSub1 = new FrmSub1(this);
            FrmSub2 frmSub2 = new FrmSub2(this);
            frmSub1.Show();
            frmSub2.Show();
        }
    
        /// <summary>
        /// 文本框改变事件,调用通知订阅者方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtMain_TextChanged(object sender, EventArgs e)
        {
            this.Message = txtMain.Text;
            NotifyObservers();
        }
    
        /// <summary>
        /// 注册订阅者
        /// </summary>
        /// <param name="observer"></param>
        public void RegisterObserver(IObserver observer)
        {
            _observers.Add(observer);
        }
    
        /// <summary>
        /// 移除订阅者
        /// </summary>
        /// <param name="observer"></param>
        public void RemoveObserver(IObserver observer)
        {
            _observers.Remove(observer);
        }
    
        /// <summary>
        /// 通知订阅者
        /// </summary>
        public void NotifyObservers()
        {
            foreach (IObserver observer in _observers)
            {
                observer.Update(Message);
            }
        }
    }
    

    子窗体类(订阅者)的代码如下:

    public partial class FrmSub1 : Form,IObserver
    {
        public FrmSub1(ISubject subject)
        {
            InitializeComponent();
            //注册
            subject.RegisterObserver(this);
        }
    	//当发布者事件发生时,订阅者需要执行的方法
        public void Update(string message,bool isShown)
        {
           txtSub.Text = message;
        }
    }
    

    上面可以看到FrmMain又依赖了FrmSub1和FrmSub2,其实这是需要另一个方法Show()。不过为表现出高层不依赖底层,我们改掉代码,在NotifyObservers(bool isShown)方法中加入对子窗体是否show的判断,从而实现了避免FrmMain依赖FrmSub1,FrmSub2
    FrmMain类的代码:

    public partial class FrmMain : Form, ISubject
    {
        private string Message { get; set; }
        private List<IObserver> _observers = new List<IObserver>();
    
    
        public FrmMain()
        {
            InitializeComponent();
        }
    
    
        private void FrmMain_Load(object sender, EventArgs e)
        {
            //FrmSub1 frmSub1 = new FrmSub1(this);
            //FrmSub2 frmSub2 = new FrmSub2(this);
            //frmSub1.Show();
            //frmSub2.Show();
            //这里我们使用了方法,摆脱了对子窗体的直接依赖
            NotifyObservers(false);
        }
    
        /// <summary>
        /// 文本框改变事件,调用通知订阅者方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtMain_TextChanged(object sender, EventArgs e)
        {
            this.Message = txtMain.Text;
            NotifyObservers(true);
        }
    
        /// <summary>
        /// 注册订阅者
        /// </summary>
        /// <param name="observer"></param>
        public void RegisterObserver(IObserver observer)
        {
            _observers.Add(observer);
        }
    
        /// <summary>
        /// 移除订阅者
        /// </summary>
        /// <param name="observer"></param>
        public void RemoveObserver(IObserver observer)
        {
            _observers.Remove(observer);
        }
    
        /// <summary>
        /// 通知订阅者
        /// </summary>
        public void NotifyObservers(bool isShown)
        {
    
            foreach (IObserver observer in _observers)
            {
                observer.Update(Message,isShown);
            }
        }
    
    }
    

    子窗体类的代码:

    public partial class FrmSub1 : Form,IObserver
    {
        public FrmSub1(ISubject subject)
        {
            InitializeComponent();
            subject.RegisterObserver(this);
        }
    
        //这里对Update做了改变,isShown为true,表示事件触发时子窗体已经显示
        public void Update(string message,bool isShown)
        {
            if (isShown)
            {
                txtSub.Text = message;
            }
            else
            {
                this.Show();
            }
    
        }
    }
    
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        FrmMain frmMain = new FrmMain();
        FrmSub1 frmSub1 = new FrmSub1(frmMain);
        FrmSub2 frmSub2 = new FrmSub2(frmMain);
        Application.Run(frmMain);
    }
    

    完整源代码参考:https://gitee.com/Alexander360/ProDotnetDesignPatternFramework45

  • 相关阅读:
    Spring基础知识
    Hibernate基础知识
    Struts2基础知识
    在eclipse里头用checkstyle检查项目出现 File contains tab characters (this is the first instance)原因
    java后台获取cookie里面值得方法
    ckplayer 中的style.swf 中的 style.xml 中的修改方法
    java hql case when 的用法
    Windows下Mongodb安装及配置
    Mongodb中经常出现的错误(汇总)child process failed, exited with error number
    Mac 安装mongodb
  • 原文地址:https://www.cnblogs.com/AlexanderZhao/p/12184407.html
Copyright © 2011-2022 走看看