原文地址:

http://www.tuicool.com/articles/F7reem

http://blog.csdn.net/yl2isoft/article/details/11711833

前段时间,公司同事开发了一个小工具,在工具执行过程中, 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;
             }
              || inputNumber<)
             {
                 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)
         {
             ;
             ; 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=" ResizeMode="NoResize">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="252*" />
            <ColumnDefinition Width="251*" />
        </Grid.ColumnDefinitions>
        <Button Content=" />
        <Label Content=" HorizontalAlignment="Left" Margin="36,93,0,0" Name="label1" VerticalAlignment="Top" />
        <TextBox Height=" />
        <TextBox Height=" />
    </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 ,求和,界面不再存在卡死现象。

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

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

    原文:Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析 前段时间,公司同事开发了一个小工具,在工具执行过程中,UI界面一直处于卡死状态. 通过阅读代码发现,主要是 ...

  2. WPF Dispatcher.BeginInvoke子线程更新UI

    在开发WPF应用时出现:”调用线程无法访问此对象,因为另一个线程拥有该对象.“ 是因为UI线程是WPF应用的主线程,若尝试子线程更新UI线程应使用Dispatcher.BeginInvoke()或者I ...

  3. Wpf Dispatcher.BeginInvoke((Action)delegate{}));

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/w ...

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

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. openfire+asmack搭建的安卓即时通讯(五) 15.4.12

    这一篇博客其实是要昨天写的,但昨天做了作修改就停不下来了,这次的修改应该是前期开发的最终回了,其余的功能有空再做了,下周可能要做一些好玩的东西,敬请期待! 1.修改下Logo:(Just We) ht ...

  2. Dubbo架构设计详解(转自shiyanjun.cn)

    Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模 ...

  3. Ajax类库需要注意的问题

    构建Ajax类库时,注意四步就可以了: 1:创建Ajax  对象 2:链接服务器 3:发送请求 4:返回响应 下面是我自己写的一个Ajax类库: function ajax(url,fnn,fai) ...

  4. NVIDIA Physix Unity3D

    提升机器的3D性能 在公司用的台式机看配置不会很差,但是在处理3D方面特别地无奈!例如开个PS,3d MAX就会卡的半死,再多开一会儿就直接未响应,然后机器重启. 真无奈啊,公司暂时也不会给我换电脑或 ...

  5. java 21 - 14 Properties类

    类 Properties Properties 类表示了一个持久的属性集.Properties 可保存在流中或从流中加载.属性列表中每个键及其对应值都是一个字符串. 注意:Properties是Has ...

  6. gridpanel分组汇总

    [ExtJS5学习笔记]第三十节 sencha extjs 5表格gridpanel分组汇总 2015-05-31     86 本文地址:http://blog.csdn.net/sushengmi ...

  7. 023医疗项目-模块二:药品目录的导入导出-从数据库中查出数据用XSSF导出excel并存放在虚拟目录最后下载(包括调试)

    我们要实现的效果:     进入到这个页面后,输入要查询的条件,查询出药品表的数据,然后按下导出按钮 ,就会在服务器的一个目录下生成一个药品表的excel表格.  点击"导出"之后 ...

  8. WinForm中异步加载数据并使用进度条

    在WinForm程序中,有时会因为加载大量数据导致UI界面假死,这种情况对于用户来说是非常不友好的.因此,在加载大量数据的情况下,首先应该将数据加载放在另一线程中进行,这样保证了UI界面的响应:其次可 ...

  9. [转]20位活跃在Github上的国内技术大牛

    FROM : http://blog.csdn.net/yaoxtao/article/details/38518933 20位活跃在Github上的国内技术大牛 本文列举了20位在Github上非常 ...

  10. vrrp两用

    早上想了想vrrp的使用,1,网关冗余 2,服务器热备 思想稍微有点不一样.主要在于监控口 服务器的话有心跳线,用户同步一些配置和迁移一些服务.达到热备的目的.:牵涉到四个优先级:建议这样排序: 主机 ...