首页 > 代码库 > [02]WPF异步响应,自定义事件、委托——多线程处理

[02]WPF异步响应,自定义事件、委托——多线程处理

题记

     在编写有GUI的程序时,会遇到这样一种情形:用户点击了一个按钮,程序处理这个事件,然而这个处理过程耗时间较长。我们不想让软件卡在这里,而是让用户可以继续使用其他的软件功能。这种问题可以用多线程的事件响应来解决。这里,我就WPF的多线程事件响应做一个简单的归纳。

 

一、简单的异步的事件响应

     在WPF中,针对简单的多线程处理过程,我们可以使用.NET自带的BackgroundWork完成。BackgroundWork的处理过程就是异步的,不会让用户界面停止响应。

using System.ComponentModel;using System.Threading;namespace TestProject{        public partial class MainWindow : Window    {        //...                    private void Button1_Click(object sender, RoutedEventArgs e)        {            //声明            BackgroundWorker worker = new BackgroundWorker();                        // worker 要做的事情 使用了匿名的事件响应函数            worker.DoWork += (o, ea) =>            {                //WPF中线程只能控制自己创建的控件,                //如果要修改主线程创建的MainWindow界面的内容,                //可以委托主线程的Dispatcher处理。                //在这里,委托内容为一个匿名的Action对象。                this.Dispatcher.Invoke((Action)(() =>                {                    this.TextBox1.Text = "worker started";                }));                Thread.Sleep(1000);            };            // worker 完成事件响应            worker.RunWorkerCompleted += (o, ea) =>            {                this.Dispatcher.Invoke((Action)(() =>                {                    this.TextBox1.Text = "worker finished";                }));            };                        //注意:运行了下面这一行代码,worker才真正开始工作。上面都只是声明定义而已。            worker.RunWorkerAsync();        }                //...            }}

 

二、自定义事件的多线程处理过程

     有时候,在我们创建的新的线程中,可能有一些事件需要主线程处理。对于这种比较复杂的异步处理,可以自定义事件,用C#中的委托(delegate)实现。

     

      MyThread.cs (自定义事件)     

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.IO;namespace TestProject{    //定义 自定义事件的参数类型    public class MyEventArgs : EventArgs    {        //参数可以携带值,方便处理程序使用        public readonly int value;        public MyEventArgs(int v)        {            value = v;        }    }    class MyThread    {        //...                //定义delegate        public delegate void MyEventHandler(object sender, MyEventArgs e);                //声明 自定义事件        public event MyEventHandler MyEvent;        //...        //触发事件        protected virtual void OnMyEvent(MyEventArgs e)        {            if (MyEvent != null)            {                MyEvent(this, e);            }        }        //...                //测试函数        public void Test()        {            System.Threading.Thread.Sleep(1000);            this.OnMyEvent(new MyEventArgs(100));            System.Threading.Thread.Sleep(2000);        }    }}

 

      MainWindows.xaml.cs

using System.ComponentModel;using System.Threading;namespace TestProject{        public partial class MainWindow : Window    {        //...                //测试        private void Button2_Click(object sender, RoutedEventArgs e)        {            MyThread myThread = new MyThread();                        //为myThread的MyEvent事件声明一个响应函数            myThread.MyEvent += MyThread_MyEvent;                        //定义新的线程            Thread thread = new Thread(new ThreadStart(myThread.Test));                        //开始新的线程            thread.Start();        }                // 新的线程中 MyEvent 的响应函数        public void MyThread_MyEvent(object sender, MyEventArgs e)        {            //同样,如果想要修改主界面的控件,            //需要委托主线程的Dispatcher来处理。            this.Dispatcher.Invoke((Action)(() =>            {                this.TextBox2.Text = "MyEvent triggered";            }));        }                //...            }}

 

总结

     以上介绍了两种情况下,WPF多线程的实现方法。第一种可以满足一般的需求,例如:后台加载文件。第二种主要针对后台处理时有特殊的事件需要前台响应,例如:后台加载文件,每当加载满1M时,在MainWindow展示特定内容给用户。

[02]WPF异步响应,自定义事件、委托——多线程处理