[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展示特定内容给用户。

时间: 2024-10-12 18:35:53

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

【2016-11-11】【坚持学习】【Day24】【WPF 自定义控件 附加属性 自定义事件】

UserControl ,自定义控件. 这里刚刚想到一个问题.什么时候应该用usercontrol 定义一个控件.什么时候应该重写控件的template和样式,实现新效果. 引用一下人家的话:http://www.cnblogs.com/denghejun/p/3671061.html 我的理解: Usercontrol应该是一个带有功能,带有行为的控件.而一些简单的模型,样式效果,应该都可以用Template实现.它大部分是给呈现效果服务,当然,它可以带有很多事件触发器. 另外,在一些复杂的功

WPF UserControl响应窗体的PreviewKeyDown事件

目的 在UserControl页面实现通过快捷键打开新建窗口 实现过程 监听Window窗体的PreviewKeyDown 其实,使用KeyDown事件也是可以的 页面代码 <Window x:Class="WpfApp2.MainWindow" PreviewKeyDown="Window_PreviewKeyDown" ......> 后置页代码 private void Window_PreviewKeyDown(object sender, Ke

C#委托五(自定义事件)

事件: "在发生其他类或对象关注的事情时,类或对象可以通过事件通知他们.发送(或引发)事件的类称为"发行者",接受(或处理)事件的类称为"订户"." 上面这句话描述了事件的最本质功能,用于底层通知上层.正常的架构设计都是分层结构,而分层结构有一点很重要的就是底层对于上层的无知,当初这样设计是为了解耦,为了更好的面向对象,但是带来的问题是如何解决自下而上的信息流.因为自上而下的调用,我们通过接口就可以搞定一切了,上层可以看到下层提供的服务接口,那么

自定义 ViewGroup 支持无限循环翻页之三(响应回调事件)

大家如果喜欢我的博客,请关注一下我的微博,请点击这里(http://weibo.com/kifile),谢谢 转载请标明出处,再次感谢 ####################################################################### 自定义 ViewGroup 支持无限循环翻页系列 自定义 ViewGroup 支持无限循环翻页之一(重写 onLayout以及 dispatchDraw) 自定义 ViewGroup 支持无限循环翻页之二(处理触摸事件)

利用委托自定义事件

事件,这个大家都非常熟悉的名词,代码里几乎离不开它.但是我们平时都是用现成的事件,如果满足不了我们的需求怎么办?那就只能咱自己写了,那么问题就来了,如何自定义事件呢? 在这之前,我们就必须先了解事件与委托的干系是什么,只有弄清楚事物的本质,我们才能掌握住事物的灵魂. 我们先看看最常用的一个事件:Form_Load() public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs

wpf自定义控件中使用自定义事件

wpf自定义控件中使用自定义事件 1 创建自定义控件及自定义事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36     /// <summary>     /// 演示用的自定义控件     /// </summary>     public class ExtButton : Button     {         public

由自定义事件到vue数据响应

前言 除了大家经常提到的自定义事件之外,浏览器本身也支持我们自定义事件,我们常说的自定义事件一般用于项目中的一些通知机制.最近正好看到了这部分,就一起看了下自定义事件不同的实现,以及vue数据响应的基本原理. 浏览器自定义事件 定义 除了我们常见的click,touch等事件之外,浏览器支持我们定义和分发自定义事件. 创建也十分简单: //创建名为test的自定义事件 var event = new Event('test') //如果是需要更多参数可以这样 var event = new Cu

WPF触屏Touch事件在嵌套控件中的响应问题

原文:WPF触屏Touch事件在嵌套控件中的响应问题 前几天遇到个touch事件的坑,记录下来以增强理解. 具体是 想把一个listview嵌套到另一个listview,这时候如果list view(子listview)的内容过多超过容器高度,它是不会出现滚动条压缩内容区域的,反而会将滚动区域转移到外面的list view(父listview),这个无可争议,但这个问题开始没留意,为待会的坑埋下伏笔. 因为 然后就是设置鼠标滚轮. 首先我使用了MouseWheel事件,奇怪的是它明明是个路由事件

WPF异步载入图片,附带载入中动画

原文:WPF异步载入图片,附带载入中动画 WPF异步载入图片,附带载入中动画 最近,在做一个WPF项目.项目中有一个需求,就是以列表的方式显示出项目图片.这些图片有的存在于互联网上,有的存在于本地磁盘.存在本地磁盘的文件好说,主要是存在于网络的图片.因为存在于网络的图片,在载入时需要耗费时间,如果直接给Image控件绑定URI属性的话,会造成界面卡顿.为了提供更好的体验,要求有类似网页中图片载入中的特效. 经过两天的研究,我翻看了爱壁纸HD For Windows的源代码(你懂得).终于完成了这