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

Posted alexanderzhao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了观察者模式的应用: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

以上是关于观察者模式的应用:Winform窗体之间传值的主要内容,如果未能解决你的问题,请参考以下文章

WPF C#怎么窗体间传值

WinForm开发,窗体显示和窗体传值相关知识总结

Visual Studio 中两个窗体(WinForm)之间相互传值的方法

winform独立窗体之间传值的简单方法

Winform中利用委托实现窗体之间的传值

Winform 单例模式下,能否传值?怎么传值?