WPF常用技巧-多线程处理

WPF支持单线程单元模型,该模型与在Windows窗体应用程序中使用的模型非常类似,具有以下几条原则:

  • WPF元素具有线程关联性。创建WPF元素的线程拥有所创建的元素,其他线程不能直接与这些WPF元素进行交互。
  • WPF对象都在类层次的某个位置继承自DispatcherObject类,DispatcherObject类提供了少量成员,用于核实访问WPF对象的代码是否在正确的线程上执行,如果没有,是否能切换位置。

Dispatcher类

Disparcher类的实例为一个调度程序,管理在WPF应用程序中发生的操作。调度程序拥有应用程序线程(也就是拥有线程中创建的WPF元素),并管理工作项队列,当应用程序运行时,调度程序接受新的工作请求,并且一次执行一个任务。

在WPF中,有一个基类DisparcherObject,所有WPF组件如WindowButton等都继承自DispatcherObject,当某个线程中第一次实例化DisparcherObject的子类时,会创建一个调度程序。因此,如果开多个线程,每个线程都展示独立的窗体,那么将会创建多个调度程序。但在一般情况下,开发应用程序只使用一个用户界面线程和一个调度程序。

  • 注意区分,DispatcherDispatcherObject并不是父子类。

DispatcherObject类

一、常用成员

Dispatcher:属性成员,返回管理该对象的调度程序。

CheckAccess():如果代码在正确的线程上使用对象,就返回true,否则返回false

VerifyAccess():如果代码在正确的线程上使用对象,就什么也不做,否则抛出InvalidOperationException异常。

  • 一般情况下我们不需要自己去调用VerifyAccess()方法,WPF对象为保护自身会频繁调用VerifyAccess()方法,从而不可能在错误的线程中长时间使用一个对象。

在需要跨线程访问控件时,可以通过控件的调度程序,即Dispatcher对象的Invoke()BeginInvoke()方法来将代码安排为调度程序的任务,然后控件的调度程序会去执行这些代码。

BeginInvoke(DispatcherPriority priority, Delegate method):第一个参数指示任务的优先级,为DispatcherPriority枚举类型,一般情况下使用DispatcherPriority.Normal即可,如果任务不需要被立即完成,也可以使用更低的优先级;第二个参数为一个方法的委托Delegate类型,该委托指向具体任务的方法。

  • DispatcherPriority.ApplicationIdle:等待应用程序在完成所有其他工作时执行指定的任务。
  • DispatcherPriority.SystemIdle:比ApplicationIdle优先级更低,直到整个系统都处于休息状态,并且CPU处于空闲状态才执行。
private void Button_Click(object sender, RoutedEventArgs e)
{Task.Run(() =>{Change();});
}private void Change()
{if (!CheckAccess()){Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>{lbl_Test.Content = "Test-ChangeOne";})); ;}else{lbl_Test.Content = "Test-ChangeTwo";}
}

Invoke()Invoke()函数的参数是一个ActionFunc类型对象,与BeginInvoke的区别是,BeginInvoke是异步执行的,Invoke同步执行的,使用Invoke时,如果执行任务比较耗时,会导致UI界面卡死。

private void Button_Click(object sender, RoutedEventArgs e)
{Task.Run(() =>{Change();});
}private void Change()
{if (!CheckAccess()){Dispatcher.Invoke(DispatcherPriority.Normal, new Action(({Thread.Sleep(5000);//这里做延时,会发现UI界面卡住lbl_Test.Content = "Test-ChangeOne";})); }else{lbl_Test.Content = "Test-ChangeTwo";}
}

二、Dispacher调度器对象的获取

常见的获取Dispacher调度器的方式有如下三种:

直接调用Dispatcher属性

由于WPF中的绝大多是类型都是DispatcherObject的子类,因此继承了Dispatcher属性,可以直接在类中通过Dispatcher来获取。(视图的后台代码继承了WindowUserControl等都是DispatcherObject的子类)

public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();Dispatcher.BeginInvoke(() =>{});}
}

通过Dispatcher的静态属性

通过System.Windows.Threading命名空间下的Dispatcher属性可以获得当先线程的调度程序对象。

  • 注意,这里是获取当前线程的调度器对象,并不一定能获得UI的调度器对象。
var dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;

通过Application获取

如果是在应用程序中,如WPF,可以通过Application.Current.Dispatcher来获取当前UI线程的调度程序对象。

  • 这里可以直接获取到当前应用的UI调度器对象
var dispatcher = Application.Current.Dispatcher;

DispatcherTimer

在WPF中常常会遇到按照一定间隔时间执行同一个任务的场景,这个时候就可以使用定时器DispatcherTimer来进行定时任务的设定了。

  • DispatcherTimer执行任务的线程是在UI调度器所在线程上,所以可以在执行任务中直接访问和操作UI元素,而不会引发线程安全问题。

常用的两种创建方式:

//第一种
private DispatcherTimer? _timer;
private void MyTask(){ ... }
public MainWindowViewModel()
{_timer = new DispatcherTimer(TimeSpan.FromSeconds(1), DispatcherPriority.Loaded, new EventHandler((s, e) => MyTask()), Application.Current.Dispatcher);
}//第二种
private DispatcherTimer _timer = new DispatcherTimer();
private void MyTask(object? sender, EventArgs e) { ... }
public MainWindowViewModel()
{_timer.Interval = TimeSpan.FromSeconds(1);_timer.Tick += MyTask;
}

计时器的开始与停止:

_timer?.Start();
_timer?.Stop();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java后端开发——SSM整合实验

文章目录 Java后端开发——SSM整合实验一、常用方式整合SSM框架二、纯注解方式整合SSM框架 Java后端开发——SSM整合实验 一、常用方式整合SSM框架 1.搭建数据库环境:MySQL数据库中创建一个名称为ssm的数据库,在该数据库中创建一个名称为tb_book的表 …

CAD数据转pcl可读数据

//-----------------------读取CAD模型------------------------vtkSmartPointer<vtkSTLReader> reader vtkSmartPointer<vtkSTLReader>::New();reader->SetFileName("data.stl");reader->Update();//----------------------转出到poly格式------…

如何顺滑使用华为云编译构建平台?

这两年平台构建服务需求越来越大&#xff0c;却一直苦于找不到一些指南&#xff0c; 这里特意写了一篇&#xff0c; 对在学习代码阶段和新手程序员朋友也蛮友好&#xff0c; 配置真的也不难&#xff0c; 也特别适合想尝试从0到1做个APP的朋友了。 以华为云的CodeArts Build为例…

CCF模拟题 202303-1田地丈量

问题描述 试题编号&#xff1a; 202303-1 试题名称&#xff1a; 田地丈量 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 512.0MB 问题描述&#xff1a; 西西艾弗岛上散落着 n 块田地。每块田地可视为平面直角坐标系下的一块矩形区域&#xff0c;由左下角坐标 (x1,y1) 和右…

OpenBLAS 的静态库命名分析 — — 以 x86_64 的静态库为例

在不同的机器上&#xff0c;生成的openblas生成的lib的名字可能是这样的&#xff1a; libopenblas_skylakexp-r0.3.26.dev.a libopenblas_skylakexp-r0.3.26.dev.so 也可能是这样的&#xff1a; liblapack_static_haswellp-r0.3.25.dev.a libopenblas_haswellp-r0.3.26.dev…

面试算法91:粉刷房子

题目 一排n幢房子要粉刷成红色、绿色和蓝色&#xff0c;不同房子被粉刷成不同颜色的成本不同。用一个n3的数组表示n幢房子分别用3种颜色粉刷的成本。要求任意相邻的两幢房子的颜色都不一样&#xff0c;请计算粉刷这n幢房子的最少成本。例如&#xff0c;粉刷3幢房子的成本分别为…

Linux-添加虚拟内存,不添加硬盘方式操作

在linux中&#xff0c;当物理内存mem不足时&#xff0c;就会使用虚拟内存(swap分区) 例如增加2G虚拟内存&#xff0c;操作如下: 1.查看内存大小 [rootlocalhost ~]# free -m 2.创建要作为swap分区的文件:增加1GB大小的交换分区&#xff0c;则命令写法如下&#xff0c;其中的cou…

1. 认识SPSS

使用的是IBM SPSS statistics 25&#xff0c;参考教材《统计分析与SPSS的应用》 一、安装和启动 具体安装过程是参考spss下载以及安装详细教程这篇文章&#xff0c;下载安装包然后按他的步骤获取用户许可证即可。 二、主要窗口 数据编辑器窗口data editor 是SPSS的主程序窗…

【C++之单例模式】

C之单例模式 前言介绍1、单例模式是什么&#xff1f;1.1 实现单例模式的三个要点1.2 单例模式分类 2. 懒汉式2.1 懒汉实现&#xff1a;基础方法2.2 懒汉实现&#xff1a;基于单锁2.3 懒汉实现&#xff1a;基于双重检测锁2.4 懒汉实现&#xff1a;基于双重检测锁和资源管理2.4.1…

ssm基于Vue的戏剧推广网站论文

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统戏剧推广信息管理难度大&#xff0c;容错率低&#xff0c…

代码随想录day23 二叉岁终章

669. 修剪二叉搜索树 题目 给定一个二叉搜索树&#xff0c;同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[L, R]中 (R>L) 。你可能需要改变树的根节点&#xff0c;所以结果应当返回修剪好的二叉搜索树的新的根节点。 思考 这题有个…

2024年中职网络安全——Windows操作系统渗透测试(Server2105)

Windows操作系统渗透测试 任务环境说明&#xff1a; 服务器场景&#xff1a;Server2105服务器场景操作系统&#xff1a;Windows&#xff08;版本不详&#xff09;&#xff08;封闭靶机&#xff09;需要环境加Q 目录 1.通过本地PC中渗透测试平台Kali对服务器场景进行系统服务…

Docker 部署后端项目自动化脚本

文章目录 开机自启动docker打包后端项目Dockerfile文件脚本文件使用 开机自启动docker systemctl enable dockersystemctl is-enabled docker打包后端项目 这里的项目位置是target同级目录 1.在项目下面新建一个bin目录 新建一个package.txt 写入下方代码后 后缀改为.bat ec…

配置git服务器

第一步&#xff1a; jdk环境配置 &#xff08;1&#xff09;搜索【高级系统设置】&#xff0c;选择【高级】选项卡&#xff0c;点【环境变量】 &#xff08;2&#xff09;在【系统变量】里面&#xff0c;点击【新建】 &#xff08;3&#xff09;添加JAVA_HOME环境变量JAVA_HO…

展开运算符(Spread Operator)

展开运算符&#xff08;Spread Operator&#xff09;是ES6中引入的一种语法&#xff0c;使用三个连续的点&#xff08;...&#xff09;表示。它可以在多种场合下使用&#xff0c;主要用途是“展开”数组或对象中的元素或属性。 使用展开运算符的几种常见情景&#xff1a; 在函…

小程序学习基础(页面加载)

打开首页&#xff0c;然后点击第一个按钮进去心得页面 进入心得页面以后 第一个模块是轮播图用的是swiper组件&#xff0c;然后就是四个按钮绑定点击事件&#xff0c;最后就是下拉刷新&#xff0c;下拉滚动&#xff0c;上拉加载。代码顺序wxml,js,wcss,json。 <!--pages/o…

【开源商城推荐-LGPL-3.0】ts-mall 聚惠星商城

dts-shop: 聚惠星商城 DTS-SHOP&#xff0c;基于 微信小程序 springboot vue 技术构建 &#xff0c;支持单店铺&#xff0c;多店铺入驻的商城平台。项目包含 微信小程序&#xff0c;管理后台。基于java后台语言&#xff0c;已功能闭环&#xff0c;且达到商用标准的一套项目体…

金和OA C6 MailTemplates.aspx SQL注入漏洞

文章目录 产品简介漏洞概述指纹识别漏洞利用修复建议 产品简介 金和OA协同办公管理系统软件&#xff08;简称金和OA&#xff09;&#xff0c;本着简单、适用、高效的原则&#xff0c;贴合企事业单位的实际需求&#xff0c;实行通用化、标准化、智能化、人性化的产品设计&#…

Day05

19.用户与权限管理 19.1 用户管理 MySQL用户可以分为普通用户和root用户。root用户是超级管理员&#xff0c;拥有所有权限&#xff0c;包括创建用户、删除用户和修改用户的密码等管理权限&#xff1b;普通用户只拥有被授予的各种权限。 MySQL提供了许多语句用来管理用户账号…

kotlin的注解

在Kotlin中&#xff0c;注解&#xff08;Annotations&#xff09;是一种用于在程序代码中添加元数据的特殊标记。它们提供了对代码的描述性信息&#xff0c;但本身并不会影响程序的运行。注解可以应用于类、方法、属性等程序元素上&#xff0c;用于提供关于这些元素的额外信息。…