原文:Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

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

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

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

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

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

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

以下为cs代码:

using System;
using System.Windows;
using System.Threading; namespace DispatcherExample
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
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代码:

<Window x:Class="DispatcherExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="求(和)你亿万次~~" Height="350" Width="525" ResizeMode="NoResize">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="252*" />
<ColumnDefinition Width="251*" />
</Grid.ColumnDefinitions>
<Button Content="计算和值" Height="23" HorizontalAlignment="Left" Margin="213,168,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" Grid.ColumnSpan="2" />
<Label Content="输入1亿-25亿间的数字:" Height="28" HorizontalAlignment="Left" Margin="36,93,0,0" Name="label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="158,96,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Grid.ColumnSpan="2" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="35,96,0,0" Name="textBox2" VerticalAlignment="Top" Width="177" Text="结果看这里..." Grid.Column="1" />
</Grid>
</Window>

执行程序,界面如下:

输入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。

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

Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析的更多相关文章

  1. WPF--Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

    原文地址: http://www.tuicool.com/articles/F7reem http://blog.csdn.net/yl2isoft/article/details/11711833 ...

  2. 使用multiprocessing解决PyMuPDF不支持多线程加载导致的界面卡死无响应问题,及一个PyQt5实现的简易PDF阅读器例子

    最近在用PyMuPDF实现一个PDF阅读器,发现PyMuPDF在加载某些epub时耗时非常长,有的长达10几秒,会导致界面卡死无响应. 尝试用多线程后台加载,发现还是不能解决问题,和作者交流(issu ...

  3. io流中read方法使用不当导致运行异常的一点

    public class CopyMp3test { public static void main(String[] args) throws IOException { FileInputStre ...

  4. 【C#】多线程解决UI界面卡死的问题

    一个经典的例子: http://www.cnblogs.com/wangchuang/p/4485797.html 问题: 都说Invoke是同步的,BeginInvoke是异步的,但为何用Begin ...

  5. 关于windows系统DPI增大导致字体变大的原因分析

    最近再学习WPF开发,其中提到一个特性“分辨率无关性”,主要功能就是实现开发的桌面程序在不同分辨率的电脑上显示时,会根据系统的DPI自动进行UI的缩放,从而不会导致应用程序的失真. 这个里面就提到了个 ...

  6. 关于Control.Dispatcher.BeginInvoke卡界面

    Control.Dispatcher.BeginInvoke里的逻辑由UI线程执行,如果内部包含耗时操作就会造成界面卡住. Action.BeginInvoke里的逻辑,将在一个新开的线程中执行,而不 ...

  7. C# 串口关闭时主界面卡死原因分析

    目录 问题描述 查找原因 SerialPort类Open()方法 SerialPort类Close()方法 死锁原因 解决死锁 总结 问题描述 前几天用SerialPort类写一个串口的测试程序,关闭 ...

  8. 非UI线程更新UI界面的各种方法小结

    转载:https://www.cnblogs.com/xiashengwang/archive/2012/08/18/2645541.html 我们知道只有UI线程才能更新UI界面,其他线程访问UI控 ...

  9. WPF子线程更新UI(Dispatcher.BeginInvoke)

       在做WPF开发时,如果直接在子线程里更新UI会报错—–“调用线程无法访问此对象,因为另一个线程拥有该对象.”,这是因为WPF禁止在非UI线程里直接更新UI界面. 解决方案:   在子线程里调用D ...

随机推荐

  1. LeetCode_Integer to Roman

    Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 t ...

  2. 用JSON 和 Google 实现全文翻译

    unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...

  3. HtmlTextNode & HtmlCommentNode

    在HtmlAgilityPack里,HtmlTextNode对应的是文本节点.这是一个非常简单的一个类,方法和字段都比较少. 一.属性 override string InnerHtml { get; ...

  4. VC6.0 显示代码行号和WndTab插件

    VC6.0是一款比较稳定的功能强大的IDE,目前也有很多人在使用.但美中不足的是它不能像其他IDE那样显示行号. 这里需要用到一个插件VC6LineNumberAddin,下载地址:http://fi ...

  5. bzoj1645 [Usaco2007 Open]City Horizon 城市地平线

    Description Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at ...

  6. 剑指offer-面试题5.从尾到头打印链表

    题目:输入一个链表的头结点,从尾到头反过来打印出每个结点的值. 刚看到这道题的小伙伴可能就会想,这还不简单,将链表反转输出. 但是这种情况破坏了链表的结构. 如果面试官要求不破坏链表结构呢,这时候我们 ...

  7. ZOJ3477&JAVA大数类

    转:http://blog.csdn.net/sunkun2013/article/details/11822927 import java.util.*; import java.math.BigI ...

  8. Extjs实现进度条

    做Extjs开发中,往往后台程序可能要执行一段时间才能得到返回结果,加入进度条可以提高客户体验度,以下为两种便捷的方式: 1.提交数据前用Ext.Msg.wait('提示','正在处理数据,请稍候') ...

  9. poj 3301 Texas Trip(几何+三分)

    Description After a day trip with his friend Dick, Harry noticed a strange pattern of tiny holes in ...

  10. A Simple Problem with Integers(100棵树状数组)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K ...