观察者模式的应用: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窗体之间传值的更多相关文章

  1. C#使用事件方式Winform窗体之间传值

    [摘自:http://www.cnblogs.com/codeToUp/p/5371062.html] 工程的源代码地址:https://github.com/yes-or-no/WinFormTra ...

  2. WinForm窗体之间传值

    当程序需要将一个窗体中的一些信息传给另一个窗体并让其使用时,就需要用到这个知识点 方法一:通过接受参数的窗体的构造函数传值 例:现有Form1和Form2两个窗体,二者都包含一个文本框,Form1还包 ...

  3. C# Winform窗口之间传值的多种方法浅析(转)

    摘要http://www.jb51.net/article/63837.htm 这篇文章主要介绍了C# Winform窗口之间传值的多种方法浅析,本文起讲解了通过构造器传值.通过属性传递.通过事件携带 ...

  4. c# winform 窗体之间的传参

    说起winform程序中窗体之间的参数互传,大家找度娘会找到很多方法: 1.在窗体类中创建全局变量,类型为公开.静态的: 2.在窗体类中定义狗仔函数: 3.通过实践来船体参数: 这三种思路完全来自于霖 ...

  5. C# winform窗体间传值(使用委托或事件)

    窗体间传值 今天得空,刚好看到网上好多人再找winform窗体间传值的问题,由于昨天项目的优化的感觉不错,就写了个C# winform窗体间传值的demo,希望能给需要的人的带来帮助: 工程的源代码地 ...

  6. winform 窗体间传值

    WinForm 两窗体之间传值实例 2010-12-27 22:10:11|  分类: 学业|举报|字号 订阅     下载LOFTER我的照片书  |     窗体Form1和Form2 Form2 ...

  7. windows form (窗体) 之间传值小结

    windows form (窗体) 之间传值小结   windows form (窗体) 之间传值小结 在windows form之间传值,我总结了有四个方法:全局变量.属性.窗体构造函数和deleg ...

  8. c# 日常记录,(获取系统时间、return),一些文件隐藏无法引用,c#多个窗体之间传值

    1.获取系统时间 DateTime.Now.ToString(); DateTime dt =DateTime.Now; dt.AddDays(1); //增加一天 dt.AddDays(-1);// ...

  9. winform窗体 小程序【打开多个窗体、窗体之间传值、打开唯一窗体】

    1.打开多个窗体 2.窗体之间的传值 3打开唯一窗体

随机推荐

  1. java方法里的属性

    访问控制符:访问控制符限定方法的可见范围,或者说是方法被调用的范围.方法的访问控制符有四种,按可见范围从大到小依次是:public.protected,无访问控制符,private.其中无访问控制符不 ...

  2. Laravel5 call to undefined function openssl cipher iv length() 报错 PHP7开启OpenSSL扩展失败

    在安装laravel5.5后, 访问显示报错. call to undefined function openssl cipher iv length() 经查为php7.1的OpenSSL扩展加载失 ...

  3. P1076 单词覆盖还原

    题目描述 一个长度为 \(l(3\le l\le 255)\) 的字符串中被反复贴有 boy 和 girl 两单词,后贴上的可能覆盖已贴上的单词(没有被覆盖的用句点表示),最终每个单词至少有一个字符没 ...

  4. H3C端口状态

  5. linux 一次对一个用户限制存取

    单打开设备之外的下一步是使一个用户在多个进程中打开一个设备, 但是一次只允许一个 用户打开设备. 这个解决方案使得容易测试设备, 因为用户一次可从几个进程读写, 但是 假定这个用户负责维护在多次存取中 ...

  6. Java内存溢出java.lang.OutOfMemoryError: PermGen space

    今天把以前的一个项目部署在tomcat,启动没问题.因为用到了webservice,当调用webservice中的方法时一直报内存溢出异常 Exception in thread "http ...

  7. vue-learning:26 - component - 组件三大API之一:prop

    组件三大API之一: prop prop的大小写 prop接收类型 字符串数组形式 对象形式: type / required / default / validator prop传递类型: 静态传递 ...

  8. indexdb开cai发keng实zhi践lu

    一直在维护一个用html2canvas截图转base64保存的项目,先不说html2canvas不同版本的不同坑的问题,就说转出来的这个base64字符长度实在太大了,尤其是遇到设计出图高度达到3千多 ...

  9. UVA - 11475 Extend to Palindrome (后缀数组)

    Your task is, given an integer N, to make a palidrome (word that reads the same when you reverse it) ...

  10. ASP.NET Core 连接 GitLab 与 MatterMost 打造 devops 工具

    在现代化开发工具链里面就包含了自动化的通讯工具,而日志写代码我是推到 Gitlab 平台上,我今天听了郭锐大佬的分享之后,感觉我现在的团队的自动化做的远远不够.我在他的课程上学到的最重要一句话就是做工 ...