委托/事件/异步/InvokeRequired/MultiThreading (Detegate/Event/Sync/InvokeRequired/MultiThreading )
委托事件
#region Delegate1 private void btnExe_Click(object sender, EventArgs e) { MyClass myObject = new MyClass(); myObject.WorkCompletedDelegate += TestDelegate; myObject.WorkCompleted += TestEvent; myObject.WorkCompletedDelegate(); myObject.Fire(); myObject.Fier2(); myObject.WorkCompletedDelegate(); // myObject.WorkCompleted(); // this line will raise compiling error } static void TestEvent() { Console.WriteLine("test event"); } static void TestDelegate() { Console.WriteLine("test delegate"); } public class MyClass { public delegate void CompletedEventHandler(); public event CompletedEventHandler WorkCompleted; public CompletedEventHandler WorkCompletedDelegate; public event CompletedEventHandler WorkCompleted2; public void Fier2() { WorkCompleted2 = new CompletedEventHandler(TestDelegate2); WorkCompleted2.BeginInvoke(null, null); //WorkCompleted2(TestDelegate); } public void TestDelegate2() { Console.WriteLine("test delegate2"); } public void Fire() { if (WorkCompleted != null) { this.WorkCompleted(); } if (WorkCompletedDelegate != null) { this.WorkCompletedDelegate(); } } } #endregion
Result:
#region Delegate2 private void btnDelegate_Click(object sender, EventArgs e) { Test obj = new Test(); obj.print += printout1; //绑定printout1方法 obj.print += printout2; //绑定printout2方法 obj.start(); } static void printout1() { Console.WriteLine("输出第一段字符串"); } static void printout2() { Console.WriteLine("输出第二段字符串"); } public delegate void Print(); //创建委托 class Test { ///https://www.cnblogs.com/wujingtao/p/5196834.html ///事件实际上是一个特殊的委托实例,不用事件也没有关系。 ///实际上事件只是削弱了委托的功能,event在编译器角度保护了你程序的安全, ///因为你只能使用+=、-= 来注册事件了,而不能使用 = 为事件关联方法。 ///(在委托中还可以使用=来绑定方法,不过=是一种破坏性代码,不管之前是否已经绑定的有方法了,他都会将其清除) public event Print print; //创建事件实例 public void start() { print(); //触发事件 } } #endregion
Result:
输出第一段字符串
输出第二段字符串
异步
private static int ExecuteTask1(int num) { System.Threading.Thread.Sleep(5000); return num * num; } private static int ExecuteTask2(int num) { return num * num; } /// <summary> /// 同步 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSync_Click(object sender, EventArgs e) { lblCount1.Text = ExecuteTask1(10).ToString(); lblCount2.Text = ExecuteTask2(10).ToString(); }
异步
/// <summary> /// 异步 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAsync_Click(object sender, EventArgs e) { //创建委托方法 //另外的写法:MyCalculator objMyCalc = new ExecuteTask1; MyCalculator objMyCalc = new MyCalculator(ExecuteTask1); //通过委托异步调用方法BeginInvoke(<输入和输出变量>,AsyncCallback, object AsyncState)方法:异步调用的核心 //【输入和输出变量】:表示委托对应的参数 //【Callback】:回调函数,表示异步调用后自动调用的函数 //【AsyncState】:用于向回调函数提供参数信息 //【返回值】IAsyncResult->异步操作状态接口,封装了异步执行的参数 //https://ke.qq.com/webcourse/index.html#course_id=171257&term_id=100200221&taid=930440240340217&vid=j1413w5k6wv //异步调用任务 IAsyncResult result = objMyCalc.BeginInvoke(10, null, null); lblCount1.Text = "正在计算,请稍等……"; //同时执行其它任务 lblCount2.Text = ExecuteTask2(10).ToString(); //获取异步调用的结果 int res = objMyCalc.EndInvoke(result); lblCount1.Text = res.ToString(); }
InvokeRequired
this.InvokeRequired
判断当前线程是否是UI线程。
如果this.InvokeRequired = true,你需要通过this.Invoke()传递委托去操作界面。否则直接操作即可。
对于不是UI线程上边的代码,如果需要操作UI控件,就需要使用Invoke 或者beginInvoke。
类似的,如果你在UI的线程上边访问UI控件,就可以直接访问数据。private void btnExecute1_Click(object sender, EventArgs e) { //ThreadStart()定义方法:public delegate int Thread(); //Thread objThread = new Thread(delegate() // { // for (int i = 0; i < 10; i++) // { // Console.WriteLine("i=:" + i.ToString()); // Thread.Sleep(500); // } // }); Thread objThread = new Thread(()=> { for (int i = 1; i < 100; i++) { //Console.WriteLine("i=:" + i.ToString()); if (this.lblResult1.InvokeRequired)//判断是否调用Invoke方法 { //Invoke()方法第一个参数返回值为void委托,第二个给委托对应方法传递参数 this.Invoke(new Action<string>(s => { this.lblResult1.Text = s; }), i.ToString());//i.ToString() } Thread.Sleep(500); } }); objThread.IsBackground = true; objThread.Start(); } private void btnExecute2_Click(object sender, EventArgs e) { ParameterArgs parameter; Thread objThread = new Thread(() => { for (int i = 1; i < 50; i++) { //Console.WriteLine("i=:" + i.ToString()); if (this.lblResult1.InvokeRequired)//判断是否调用Invoke方法 { //Invoke()方法第一个参数返回值为void委托,第二个给委托对应方法传递参数 //this.Invoke(new Action<string>(s => { this.lblResult2.Text = s; }), i.ToString()); parameter = new ParameterArgs(); parameter.A = i; parameter.B = i; this.Invoke(new Action<ParameterArgs>(s => { this.lblResult2.Text = add(s).ToString(); }), parameter); } Thread.Sleep(200); } }); objThread.IsBackground = true; objThread.Start(); } public int add(ParameterArgs parameter) { return parameter.A + parameter.B; } public class ParameterArgs { public int A {get;set;} public int B {get;set;} }
异步委托
//申明委托 public delegate int MyCalculator(int num, int ms); MyCalculator objMyCal = null;//定义委托 public AsyncDalegate() { InitializeComponent(); objMyCal = new MyCalculator(ExecuteTask);//委托初始化 } private int ExecuteTask(int num, int ms) { System.Threading.Thread.Sleep(ms); Console.WriteLine(num * num); return num * num; } /// <summary> /// 同时执行多个任务 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAsync_Click(object sender, EventArgs e) { //MyCalculator objMyCal = ExecuteTask;设置为全局变量,为了回调函数封装为一个 for (int i = 0; i < 10; i++) { objMyCal.BeginInvoke(10 * i, 1000 * i, MyCallBack, i);//最后一个参数i是给字段AsyncState(object类型)赋值,可以是值/类/集合 } } //回调函数 private void MyCallBack(IAsyncResult result) { //return objMyCal.EndInvoke(result); int res = objMyCal.EndInvoke(result); //异步显示结果:第一个计算结果:100 Console.WriteLine("第{0}格计算结果是:{1}", result.AsyncState.ToString(), res); } //异步编程总结 //1.异步编程是建立在委托的基础上的基础上的 //2.异步调用用的每个方法都是在独立的线程中能够执行的,因此,本质上就是一种多线程程序,也可以使简单的多线程编程 //3.比较适合在后台运行较为耗费时间的《简单的任务》并且要求任务之间是独立的,任务之间不要有直接独立访问可视化控件的内容 //4.如果后台任务要求必须按照特定的顺序执行,或则访问到特定的共享资源,异步编程不太适合,应该选择多线程编程 //https://ke.qq.com/webcourse/index.html#course_id=171257&term_id=100200221&taid=930444535307513&vid=j1413pmg05h
####多线程
/* *进程:一个正在运行的程序就是一个进程。操作系统根据进程来分配各种资源(内存)* *线程:操作系统为了提高效率会将一个进程分给多个线程,并根据线程来分配CPU执行时间* *线程特点:在具有多个CPU的计算机中,可以并行执行* *Thread类:表示托管线程,每个Thread对象都代表一个托管线程,每个托管线程都对应一个函数* *ProcessThread类型:和操作系统本地线程是一致的* */ public partial class MultiThreading : Form { public MultiThreading() { InitializeComponent(); } private void btnExecute1_Click(object sender, EventArgs e) { //ThreadStart()定义方法:public delegate int Thread(); //Thread objThread = new Thread(delegate() // { // for (int i = 0; i < 10; i++) // { // //Console.WriteLine("i=:" + i.ToString()); // if (this.lblResult1.InvokeRequired) // { // this.Invoke(new Action<string>(s => // { // this.lblResult1.Text = s; // }), i.ToString()); // } // Thread.Sleep(500); // } // }); Thread objThread = new Thread(() => { for (int i = 1; i < 10; i++) { //Console.WriteLine("i=:" + i.ToString()); if (this.lblResult1.InvokeRequired) { this.Invoke(new Action<string>(s => { this.lblResult1.Text = s; }), i.ToString()); } Thread.Sleep(500); } }); objThread.IsBackground = true; objThread.Start(); Thread objThread2 = new Thread(() => { for (int i = 1; i < 50; i++) { //Console.WriteLine(":=i=:" + i.ToString()); if (this.lblResult2.InvokeRequired) { this.Invoke(new Action<string>(s => { this.lblResult2.Text = s; }), i.ToString()); } Thread.Sleep(200); } }); objThread2.IsBackground = true; objThread2.Start(); } private void btnExecute2_Click(object sender, EventArgs e) { Thread objThread = new Thread(() => { for (int i = 1; i < 50; i++) { //Console.WriteLine(":=i=:" + i.ToString()); if (this.lblResult2.InvokeRequired) { this.Invoke(new Action<string>(s => { this.lblResult2.Text = s; }), i.ToString()); } Thread.Sleep(200); } }); objThread.IsBackground = true; objThread.Start(); } } ···