观察者模式的应用: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窗体之间传值的更多相关文章
- C#使用事件方式Winform窗体之间传值
[摘自:http://www.cnblogs.com/codeToUp/p/5371062.html] 工程的源代码地址:https://github.com/yes-or-no/WinFormTra ...
- WinForm窗体之间传值
当程序需要将一个窗体中的一些信息传给另一个窗体并让其使用时,就需要用到这个知识点 方法一:通过接受参数的窗体的构造函数传值 例:现有Form1和Form2两个窗体,二者都包含一个文本框,Form1还包 ...
- C# Winform窗口之间传值的多种方法浅析(转)
摘要http://www.jb51.net/article/63837.htm 这篇文章主要介绍了C# Winform窗口之间传值的多种方法浅析,本文起讲解了通过构造器传值.通过属性传递.通过事件携带 ...
- c# winform 窗体之间的传参
说起winform程序中窗体之间的参数互传,大家找度娘会找到很多方法: 1.在窗体类中创建全局变量,类型为公开.静态的: 2.在窗体类中定义狗仔函数: 3.通过实践来船体参数: 这三种思路完全来自于霖 ...
- C# winform窗体间传值(使用委托或事件)
窗体间传值 今天得空,刚好看到网上好多人再找winform窗体间传值的问题,由于昨天项目的优化的感觉不错,就写了个C# winform窗体间传值的demo,希望能给需要的人的带来帮助: 工程的源代码地 ...
- winform 窗体间传值
WinForm 两窗体之间传值实例 2010-12-27 22:10:11| 分类: 学业|举报|字号 订阅 下载LOFTER我的照片书 | 窗体Form1和Form2 Form2 ...
- windows form (窗体) 之间传值小结
windows form (窗体) 之间传值小结 windows form (窗体) 之间传值小结 在windows form之间传值,我总结了有四个方法:全局变量.属性.窗体构造函数和deleg ...
- c# 日常记录,(获取系统时间、return),一些文件隐藏无法引用,c#多个窗体之间传值
1.获取系统时间 DateTime.Now.ToString(); DateTime dt =DateTime.Now; dt.AddDays(1); //增加一天 dt.AddDays(-1);// ...
- winform窗体 小程序【打开多个窗体、窗体之间传值、打开唯一窗体】
1.打开多个窗体 2.窗体之间的传值 3打开唯一窗体
随机推荐
- HMM(隐马尔科夫)用于中文分词
隐马尔可夫模型(Hidden Markov Model,HMM)是用来描述一个含有隐含未知参数的马尔可夫过程. 本文阅读了2篇blog,理解其中的意思,附上自己的代码,共同学习. 一.理解隐马尔科夫 ...
- ES6学习笔记第一天
## 三.const和let **3.1 const** const用来定义常量,所谓的常量就是值一旦给定后就不变,一次定义终身不变的量 const a = 10; a = 20; 上面的a就是一个常 ...
- LRJ
//3-1 #define _CRT_SECURE_NO_WARNINGS #include <cstdio> int main() { int T; ]; scanf("%d& ...
- Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow pip命令
引言: Tensorflow大名鼎鼎,这里不再赘述其为何物.这里讲描述在安装python包的时候碰到的“No matching distribution found for tensorflow”,其 ...
- 2019-9-2-给博客添加rss订阅
title author date CreateTime categories 给博客添加rss订阅 lindexi 2019-09-02 12:57:38 +0800 2018-2-13 17:23 ...
- 【t085】Sramoc问题
Time Limit: 1 second Memory Limit: 128 MB [问题描述] Sramoc(K,M)表示用数字0,1,2,...,K-1组成的自然数中能被M整除的最小数.给定K,M ...
- 原生PHP实现Mysql数据分页功能
一. 思路整理 实现一个数据分页功能,需要有数据的总条数,每页展示的条数,和当前在第几页这三个参数 通过⌈总条数/每页展示的条数⌉可以得到总页数,比如某留言板有101条留言,每页展示10条,一那就需要 ...
- 51nod 天气晴朗的魔法 - (Kruskall最小生成树)
题目: 基准时间限制:1 秒 空间限制:131072 KB 51nod魔法学校近日开展了主题为“天气晴朗”的魔法交流活动. N名魔法师按阵法站好,之后选取N - 1条魔法链将所有魔法师的魔力连接 ...
- D3.js力导向图(适用于其他类型图)中后添加元素遮盖已有元素的问题解决
上一篇说了在D3.js中动态增加节点及连线的一种实现方式,但是有后添加元素遮盖原节点的现象,这一篇说一下出现这个现象的解决办法. 在D3.js中后添加的元素是会遮盖先添加的元素的,同时还有一个设定:后 ...
- es6笔记 day3---数组新增东西
Array.from()的作用就是把类数组转成数组.所谓类数组,就是有长度的数组 ----------------------------------------------------------- ...