近期和几位做嵌入式开发的朋友闲聊过程中,一位朋友抱怨到:这C#太难用了,我想在N个窗体(或者是N个用户组件之间)传递值都搞不定,非得要定义一个全局变量来存储,然后用定时器来刷新值,太Low了。我急切的回答道:这很简单,不就是委托的事嘛。那你来一个示例啊:朋友道。此为这篇博客的起因,所以此篇博客对于有c#开发经验的伙伴们那是小菜一喋。

一、对委托的理解

委托:同一个功能,可以根据不同的场景委托给不同的方法具体执行; 举个栗子:某位美食爱好妹子,通常自己做美食;找到男票后,就男票做美食;换男票后,就第二任男票做美食。我们把这例子委托抽象化:

定义一个委托功能:做美食;规范及流程:输入”食材“,通过”做美食“的委托,输出”美食“。

委托实现之自己做:妹子自己做美食

委托实现之一号男票做:一号男票做美食

委托实现之二号男票做:二号男票做美食

做美食这项功能,被妹子在不同的时间段分配给了不同的对象,虽然妹子,男一,男二做的美食都很好吃,但味道肯定有区别。这就是委托生活化的示例,各位看观了解否(偷笑)。

二、代码实现

上面的示例如何用代码实现,这里就不展示了(真的很简单)。下面我们换一个稍有难度和实际应用的示例,需求说明:主窗体显示一个列表,子窗体增加数据(不关闭子窗体的情况下),主窗体列表自动更新,且第二个子窗体打开后,窗体内的列表也要同时更新。

UI设计:一个主窗体,两个子窗体(A窗体:增加数据,B窗体:显示数据),一个用户组件(列表显示内容)

2.1 EventBus实现

代码如下:

public class EventBus<T>
{
private List<T> list = new List<T>(); public event EventHandler<EventBusArg<List<T>>> EventNotice;
public delegate void DelegateItemInfoEvent(List<T> items); public void Add(T item)
{
this.list.Add(item);
this.TriggerEventNotice();
} public void Remove(T item)
{
this.list.Remove(item);
this.TriggerEventNotice();
} public List<T> GetAll()
{
return this.list;
} private void TriggerEventNotice()
{
if (this.EventNotice != null)
{
this.EventNotice.Invoke(this, new EventBusArg<List<T>>()
{
Data = this.GetAll()
});
}
}
} public class EventBusArg<T> : EventArgs
{
public T Data { get; set; }
}

重点:

1. 定义了一个委托类型:DelegateItemInfoEvent(List<T> items)

2. 定义了一个事件对象:EventHandler<EventBusArg<List<T>>>

3. 事件对象的参数必须继承EventArgs对象

4. 事件依赖委托

2.2 主窗体

代码如下:

        private EventBus<ItemInfo> eventBus = new EventBus<ItemInfo>();
private EventBus<ItemInfo>.DelegateItemInfoEvent FunItem;
public Form1()
{
InitializeComponent();
this.eventBus.EventNotice += EventBus_EventNotice;
} private void EventBus_EventNotice(object sender, EventBusArg<List<ItemInfo>> e)
{
if (this.ucList1.InvokeRequired)
{
FunItem = new EventBus<ItemInfo>.DelegateItemInfoEvent(RefreshItem);
this.ucList1.Invoke(FunItem, e.Data);
}
else
{
this.RefreshItem(e.Data);
}
} private void RefreshItem(List<ItemInfo> item)
{
var ls = this.eventBus.GetAll();
this.ucList1.LoadData(ls);
}

重点:

1. 捕获事件:this.eventBus.EventNotice += EventBus_EventNotice;

2. 事件处理方法中,需要判断是否为UI线程引发,如果不是,则需要委托来进行切换线程,代码见:private void EventBus_EventNotice(object sender, EventBusArg<List<ItemInfo>> e) 方法

3. 其中FunItem是委托类型的变量,其最终的实现为RefreshItem方法

2.3 A窗体:增加数据

代码如下:

private EventBus<ItemInfo> eventBus;
public Form2(EventBus<ItemInfo> eventBus)
{
this.eventBus = eventBus;
InitializeComponent();
} private void button1_Click(object sender, EventArgs e)
{
//在UI线程
this.eventBus.Add(new ItemInfo()
{
Title = textBox1.Text,
Val = Int32.Parse(textBox2.Text)
});
} private void button2_Click(object sender, EventArgs e)
{
//跨线程
Task.Factory.StartNew(() =>
{
for(var i=; i < ; i++)
{
this.eventBus.Add(new ItemInfo()
{
Title = i.ToString() + "-Title",
Val = i
});
}
});
}

重点:

1. 传入了EventBus对象的实例,此实例与主界面的EventBus实例为同一个【这点很重要,发布和订阅的事件必须在同一实例上】

2. button2_Click事件展示的是跨线程事件,执行此代码,主界面的刷新会走委托

2.4 B窗体:订阅列表显示

代码如下:

private EventBus<ItemInfo> eventBus;
public Form3(EventBus<ItemInfo> eventBus)
{
this.eventBus = eventBus;
InitializeComponent();
this.eventBus.EventNotice += EventBus_EventNotice;
} private void EventBus_EventNotice(object sender, EventBusArg<List<ItemInfo>> e)
{
if (this.ucList1.InvokeRequired)
{
var FunItem = new EventBus<ItemInfo>.DelegateItemInfoEvent(RefreshItem);
this.ucList1.Invoke(FunItem, e.Data);
}
else
{
this.RefreshItem(e.Data);
}
} private void RefreshItem(List<ItemInfo> item)
{
var ls = this.eventBus.GetAll();
this.ucList1.LoadData(ls);
} private void Form3_FormClosing(object sender, FormClosingEventArgs e)
{
this.eventBus.EventNotice -= EventBus_EventNotice;
}

重点:

1. 事件的订阅与取消订阅,一般情况下可以在关闭窗体时取消订阅

三、回顾

1. 事件依赖委托,事件可以订阅和取消订阅,其订阅就是为事件增加委托。

2. 委托的本质还是方法(或者说是函数),只不过方法变成了一个变量,可以在运行时动态改变

3. 源码下载

C#之委托如此简单的更多相关文章

  1. .net学习之多线程、线程死锁、线程通信 生产者消费者模式、委托的简单使用、GDI(图形设计接口)常用的方法

    1.多线程简单使用(1)进程是不执行代码的,执行代码的是线程,一个进程默认有一个线程(2)线程默认情况下都是前台线程,要所有的前台线程退出以后程序才会退出,进程里默认的线程我们叫做主线程或者叫做UI线 ...

  2. C#基础系列——委托实现简单设计模式

    前言:上一篇介绍了下多线程的相关知识:C#基础系列——多线程的常见用法详解,里面就提到了委托变量.这篇简单介绍下委托的使用.当然啦,园子里面很多介绍委托的文章都会说道:委托和事件的概念就像一道坎,过了 ...

  3. C#基础:对委托的简单理解

    在编程过程中,我们习惯把数据作为参数传递给方法(例:int a=int.Parse(“20”);).是否能将一个方法传递给另一个方法呢?是不是听起来有点奇怪!!! 线程大家应该熟悉吧,在计算机中并行运 ...

  4. C#委托的简单剖析

    为什么在Button1的Click事件发生之后,button1_Click方法就会被调用呢? 实际上,在我们双击Button1的时候,IDE自动的添加了一段代码,该段代码位于“Form1.Design ...

  5. C# 委托和事件(一):最简单的委托和事件

    C#的事件基于委托,所以先说委托. 一切脱离实际场景的抽象概念新手看上去就像是在扯犊子,不错,我就是个新手.所以我需要一个实际的场景. 明天刚好考试(商务英语),考试上有两个角色(class):老师( ...

  6. C# 委托简单使用方法

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. [.NET] C# 知识回顾 - 委托 delegate (续)

    C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...

  8. .NET面试题系列[7] - 委托与事件

    委托和事件 委托在C#中具有无比重要的地位. C#中的委托可以说俯拾即是,从LINQ中的lambda表达式到(包括但不限于)winform,wpf中的各种事件都有着委托的身影.C#中如果没有了事件,那 ...

  9. [ASP.NET MVC 大牛之路]02 - C#高级知识点概要(1) - 委托和事件

    在ASP.NET MVC 小牛之路系列中,前面用了一篇文章提了一下C#的一些知识点.照此,ASP.NET MVC 大牛之路系列也先给大家普及一下C#.NET中的高级知识点.每个知识点不太会过于详细,但 ...

随机推荐

  1. ELK 学习笔记之 Kibana入门使用

    Kibana入门使用: 第一次导入索引: 修改展示时间,不然查不到数据: 点Discover,查阅数据: 如果要添加新的index: 点击Visualize, 创建chart: 点击Dashboard ...

  2. webpack loader实现

    正值前端组件化开发时代,那么必然离不开目前最火的构建工具--webpack(grunt,gulp等暂且不谈).说到这里,刚好有几个问题: 为什么运行打包命令之后,.vue 文件可以转成 .js 文件 ...

  3. 微信小程序模板消息

    1 先去微信公众平台,选择现有模板,会有一个模板编号,模板中没有的关键词,可以申请新增. 微信公众平台直达:https://mp.weixin.qq.com 模板消息对应文档直达:https://de ...

  4. BZOJ 4621: Tc605

    Description 最初你有一个长度为 N 的数字序列 A.为了方便起见,序列 A 是一个排列. 你可以操作最多 K 次.每一次操作你可以先选定一个 A 的一个子串,然后将这个子串的数字全部变成原 ...

  5. 模块的 __name__

    模块的 __name__ 每个模块都有一个名称,而模块中的语句可以找到它们所处的模块的名称.这对于确定模块是独立运行的还是被导入进来运行的这一特定目的来说大为有用.正如先前所提到的,当模块第一次被导入 ...

  6. js二次作业

    task 1:完成省城市的三级联动(包括湖南省),附代码和效果图.<!DOCTYPE html> <html> <head> <title>完成省城市的 ...

  7. [POJ2248] Addition Chains 迭代加深搜索

    Addition Chains Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5454   Accepted: 2923   ...

  8. php是做前端的吗?

    php是做前端的吗 不是,php是后台脚本语言,由服务器执行. PHP即“超文本预处理器”,是一种通用开源脚本语言.PHP是在服务器端执行的脚本语言,与C语言类似,是常用的网站编程语言.PHP独特的语 ...

  9. Maven -- 使用Myeclipse创建Maven项目

    使用Myeclipse创建Maven项目有如下几种方式: 1.创建Maven Java项目 1.1 选择新建Maven项目 1.2.选择创建简单项目 1.3.填写项目信息 1.4.创建成功后项目目录结 ...

  10. Python 命令行之旅:使用 docopt 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...