博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析
阅读量:5909 次
发布时间:2019-06-19

本文共 3080 字,大约阅读时间需要 10 分钟。

原文:

前段时间,公司同事开发了一个小工具,在工具执行过程中,UI界面一直处于卡死状态。

通过阅读代码发现,主要是由于Dispatcher.BeginInvoke()方法使用不当导致的。

本文将通过一个WPF模拟程序来演示一下界面卡死的现象,并通过修改代码来解决界面卡死的问题。

希望通过对本文的学习,大家能对Dispatcher.BeginInvoke()方法有一个新的认识。

文章开篇直接给出界面卡死的示例代码。

示例WPF程序,用来计算1~n的和值,这里的n可以是1亿~25 亿之间的某个值,通过界面录入,结果显示在n输入框后面的文本框中,既然是WPF程序,代码包含xamlcs代码两部分,本文一并给出。

以下为cs代码:

using System;using System.Windows;using System.Threading;namespace DispatcherExample{    ///     /// MainWindow.xaml 的交互逻辑    ///     public partial class MainWindow : Window    {        public MainWindow()        {            InitializeComponent();        }        private void button1_Click(object sender, RoutedEventArgs e)        {            Int64 inputNumber;            if (!Int64.TryParse(this.textBox1.Text, out inputNumber))            {                MessageBox.Show("请输入1亿-10亿皑间的整型数据!");                return;            }            if (inputNumber > 2500000000 || inputNumber<100000000)            {                MessageBox.Show("请输入1亿-10亿间的整型数据!");                return;            }            Thread newThread = new Thread(new ParameterizedThreadStart(GetResult));            newThread.Start(inputNumber);        }        private void GetResult(object inputNumber)        {            this.Dispatcher.BeginInvoke((Action)delegate()            {                this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();            });        }        private double CalcSum(Int64 inputNumber)        {            double sum=0;            for (int i = 0; i < inputNumber; i++)            {                sum +=i;            }            return sum;        }    }}

以下为xaml代码:

执行程序,界面如下:

输入2500000000,点击“计算和值”按钮,程序开始计算和值,界面卡死,无法再操作该程序(如移动位置或重新输入等)。

分析代码,发现问题应该出在下面的代码中,因为该部分代码中存在调用UI主线程的操作,此种操作不当往往会导致界面卡死的现象。

private void GetResult(object inputNumber){     this.Dispatcher.BeginInvoke((Action)delegate()     {           this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();     });}

那么,问题到底出在哪里呢?

要想弄清楚这点,还得了解一下Dispatcher.BeginInvoke()方法。

MSDN上对Dispatcher.BeginInvoke方法的解释如下

Dispatcher.BeginInvoke 方法 (Action)

在与 Dispatcher关联的线程上异步执行指定的委托。 

那么本实例中,与 Dispatcher关联的线程是什么呢?

要想弄清楚这点很简单。只要知道this.Dispatcher.BeginInvoke()中的this指的是什么就可以了。在Visual studio中将鼠标至于this上,发现this指的是当前的窗体类(如下图),即程序的主线程。

到这,我们应该知道问题出在哪里了。

原因是:在GetResult()方法中,将求和的操作交由主线程来完成,当计算未完成时,界面自然会被卡死。

通过与同事交谈了解到,他其实想要的是:新开一个线程来完成自己预想的运算(类似于示例程序中的求和运算),在结果出来后再调用主线程显示结果。

这样界面就不会出现卡死现象,但是上面的代码并没有达到预想结果。

原因前面已经交代了,因为这段代码将求和的计算仍然丢给了主线程,尽管新开了线程,但是新开线程并不进行求和运算,可以说是绕了一圈又回来了。

主线程开新线程,新线程又调用主线程。这有点像工作中的踢皮球,我给你一件事,你说不会,又踢回给我。

找到原因再修改就简单了,修改后的代码如下:

private void GetResult(object inputNumber){     double result=CalcSum((Int64)inputNumber);     this.Dispatcher.BeginInvoke((Action)delegate()     {           //this.textBox2.Text = CalcSum((Int64)inputNumber).ToString();           this.textBox2.Text = result.ToString();               });}

至于为什么要这样修改,我想:你懂的。

再次执行程序,输入2500000000,求和,界面不再存在卡死现象。

就扯到这里了,我要米西米西了,88

版权声明:本文为博主原创文章,未经博主允许不得转载。

你可能感兴趣的文章
tomecat无法启动是什么原因??
查看>>
XCode使用小记与代码管理
查看>>
spring同时集成mybatis和ibatis
查看>>
IRC 聊天工具(xchat,chatzilla,pidgin)入门教程
查看>>
Redis配置
查看>>
kafka 监控之Mx4jLoader
查看>>
wireshark windows 编译
查看>>
RidolIDE+TPM安装运行和Ridol常见bug处理(迅捷版)
查看>>
-webkit-animation- 实践
查看>>
XBImageFilters
查看>>
chpter11~函数和函数式编程
查看>>
初识R
查看>>
Hadoop之HDFS的常用命令
查看>>
分布式系统架构解决方案之Dubbo(三)--Dubbo管理端 和 Dubbo综合案例
查看>>
百度地图开发 JS API
查看>>
mysqlbackup.sh
查看>>
The function getUserId must be used with...解决办法
查看>>
分布式事物----可靠消息一致性方案
查看>>
懂得保持平衡的程序员
查看>>
Class yii\base\View
查看>>