首页 > 其他分享 > 案例题目(概括异常,如:WPF 及winfrom界面假死)

案例题目(概括异常,如:WPF 及winfrom界面假死)

时间:2023-01-14 14:45:23浏览次数:50  
标签:控件 winfrom 假死 耗时 线程 new UI WPF Dispatcher

5.1    案例题目(概括异常,如:WPF 及winfrom界面假死)

 

5.1.1            异常描述

占用主UI线程,运行耗时程序代码导致界面假死无法点击及操作。

 

 

5.1.2            原因分析

(是什么原因造成的异常,或可能由哪些原因导致异常,适当作图以便理解)

 

只有创建DispatcherObject对象的线程才能访问之,其他线程不可访问该对象,比如UI线程创建的对象其他后台线程就不可访问。但是如果直接在主UI线程添加耗时代码。就会导致界面假死。

 

 

5.1.3            解决思路

(针对原因,如何解决或改善)

 

那么如果想访问该UI线程创建的控件,就必须将一个访问该控件的方法委托给创建控件的UI线程的Dispatcher去执行,才能假借UI线程之手去访问控件。this.Dispatcher.Invoke就是使用UI线程的Dispatcher调用Invoke方法执行该委托,但是这个委托中使用了比较耗时的网络请求,也就是说该请求如果在Invoke方法中,就会占用UI线程的时间片去执行,即使放在了创建的线程中。

 

本质上this.Dispatcher.Invoke或者BeginInvoke都是主UI线程执行了委托里面的代码。

 

可参考下面代码示例理解。

 

5.1.4            对策制定

(1)         

初始化线程

方法1

入参,方法

(具体方法及修改前后图)

修改前:

Thread thread = new Thread(new ThreadStart(delegate {

    this.Dispatcher.Invoke(new Action(() => {

将action作为一个委托传给invoke方法

        // 获取控件数据并且构造参数param

耗时操作

        ...

主UI线程this

        // 请求网络

        responseText = WebServiceHandler.ObjectWebServer.getObject(param);

        // 解析响应数据 

        Object o = JsonTools<Object>.DeserializeList(responseText);

控件操作—略

        // 更新控件

        ...

    }));

}))

thread.Start();

 

如上图,

在invoke里面执行了耗时操作。该耗时操作依然占用主UI线程。不过是不是异步调用的Invoke。他在耗时操作时都会导致界面假死。具体代码段解析可参考上图及解决思路。

 

修改后:

Thread thread = new Thread(new ThreadStart(delegate {

        // 获取控件数据并且构造参数param

耗时操作

        ...

        // 请求网络

        responseText = WebServiceHandler.ObjectWebServer.getObject(param);

        // 解析响应数据 

        Object o = JsonTools<Object>.DeserializeList(responseText);

 

 

this.Dispatcher.Invoke(new Action(() => {

 

控件操作—略

        // 更新控件

        ...

    }));

}))

thread.Start();

 

解决方法就是不让耗时操作占UI主线程。具体操作就是将耗时的代码段放到invok外面,新建的线程里面。

没办法截图,凑合着看吧。

 

(2)          方法2

 

(3)                 new Thread(() =>

(4)      

(5)                 {

(6)      

(7)                     Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,

(8)      

(9)                         new Action(() =>

(10)     

(11)                        {

(12)     

(13)     

(14)                            // Dispatche 异步方法!!" + DateTime.Now.ToString();

(15)     

(16)                        }));

(17)     

(18)                  }).Start();

 

各种方法大同小异。基本思路:

1、靠另起一个线程或者异步方法跳过耗时代码这段。

2、在另起的这段代码里用Dispatcher.BeginInvoke或者Invoke委托来调用UI线程的控件,进而执行控件的更新。

3、切记不要将耗时的代码写在InVoke里面就成。

 

(3)方法3

这个方法比较复杂:除非有要持续监控并显示在主界面的内容。

 

思路

1、外围再起一个线程。以目前标准scada AlarmHandler为例。当然Timer定时器也可以,方便开启和关闭当前监听的循环(以90340CNC设备监控为例)。

 

2、在合适的位置实例化并开启该线程或者循环的监听。

 

3、该线程部分代码范例可参考AlarmHandler相关部分。原来这个部分有当前部分报警(有前端显示变更)变更,是靠委托和事件触发前端列表变更的。后面改成的public的全局变量。然后由前端UI线程开定时器去刷这个值(占主线程)。

 

 

  对于这个部分为什么不用委托和事件,而要改成占主线程的定时器去刷。是因为委托和事件的用法有问题。

 我是这么理解的。在timer定时器监控循环里面,在有监控的变量刷新(变化)的时候,触发对应委托事件,前端页面做相应的变更。这个需要在页面加载的时候订阅这个事件(当然也要靠Dispatcher.Invoke来对控件修改)。

CNCEvent.sentenceChangeAfter_DelegateHandler += new CNCEvent.SentenceChangeAfter_delegateHandler(SetSentence);

   这里我的监控画面并不是主窗体MianView。所以在界面开启关闭再开启时就会报该委托必须有一个目标(且仅有一个目标的错误。委托和事件就无法执行。根源应该是订阅的两个相同的事件。不对,就不是事件。

标签:控件,winfrom,假死,耗时,线程,new,UI,WPF,Dispatcher
From: https://www.cnblogs.com/sanzhu/p/14888357.html

相关文章

  • 界面假死
        privatevoidloadInfo(){boolret=false;Actionaction=newAction(()=>{System.Threading.Thread......
  • vs2022中打开vs2019的WPF项目的坑:XDG0005、XDG0066
    之前在vs2019中建立的WPF项目,在VS2022中打开时,XAML设计器界面显示不正常底下报的错是XDG0005与XDG0066编译和运行都没问题最后发现问题所在:原先在窗体中有一项目设定:VisualB......
  • 界面控件DevExpress WPF中文指南 - 用主题设计器的后台视图升级主题
    DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专......
  • c# .net开发 wpf框架,开发聊天、网盘、信息发布、视频播放功能
    工作之余,开发了一个小程序,网页端用vue.js框架,桌面端wpf,后台.net,集成identityserver4认证授权。前端wpf .net6框架后端.net6,微服务架构认证授权:identityserver4用......
  • WPF使用WriteableBitmap更新图像
     <Windowx:Class="WpfApp2.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.c......
  • WPF-TreeView行选中效果
    privatevoidtrvw_MouseDown(objectsender,MouseButtonEventArgse){if(e.SourceisTreeViewItemtreeViewItem){......
  • wpf 多屏显示
    wpf需要在分屏上显示窗体代码:<Windowx:Class="WpfApp1.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="ht......
  • WPF 虚拟键盘
    NuGet画廊|Hs.KeyBoard.WPF2.0.2dotnetaddpackageHs.KeyBoard.WPF--version2.0.2说明:1、支持执行前台事件2、支持命令绑定3、支持修改回车文本显示4、支持获取焦......
  • WPF-ContextMenu模板绑定数据失败;
    一、原代码:  XAML:<TreeViewx:Name="trvwProjectList"Margin="0,0,0,0"VerticalAlignment="Stretch"VerticalContentAlignment="Stretch"BorderBrush......
  • WPF-右键菜单ContextMenu
    示例:<ButtonMargin="10,10,0,0"VerticalAlignment="Top"HorizontalAlignment="Left"Content="按钮_具有右键菜单"><Button.ContextMenu>......