一、概述

在应用程序中,线程可以被看做是应用程序的一个较小的执行单位。每个应用程序都至少拥有一个线程,我们称为主线程。当调用和操作主线程的时候,该操作将动作添加到一个队列中,每个操作均按照将它们添加到队列中的顺序连续执行,但是可以通过为这些动作指定优先级来影响执行顺序,而负责管理此队列的对象称之为线程调度程序。

我们知道,WPF程序中,控件是属于UI线程的,如果试图在子线程中访问或者更新UI,就需要在子线程中通知主线程来处理UI, 通过向主线程的Dispatcher队列注册工作项,来通知UI线程更新结果。

Dispatcher提供两个注册工作项的方法:Invoke 和 BeginInvoke。

这两个方法均调度一个委托来执行。Invoke 是同步调用,也就是说,直到 UI 线程实际执行完该委托它才返回。BeginInvoke是异步的,将立即返回。

代码片段如下:

  1. this.Dispatcher.BeginInvoke((Action)delegate()
  2. {
  3. 更新UI控件ing
    });

二、MVVMLight模式下ViewModel中更新UI

通常情况下,ViewModel 不从 DispatcherObject 继承,不能访问 Dispatcher 属性。这时候,我们需要使用DispatcherHelper 组件来更新UI。

实际上,该类所做的是将主线程的调度程序保存在静态属性中,并公开一些实用的方法,以便通过统一的方式访问。

为了实现正常功能,需要在主线程上初始化该类。

通常,在 MVVM Light 应用程序中,DispatcherHelper 可以在 App.xaml.cs 或者ViewModel的构造函数中进行初始化,App.xaml.cs 是定义应用程序启动类的文件。

在 WPF 中,该类一般是在 App 构造函数中进行初始化的。

DispatcherHelper组件初始化以后,DispatcherHelper 类的 UIDispatcher 属性包含对主线程的调度程序的引用。

但是一般很少直接使用该属性,虽然确实可以使用。通常我们会使用 CheckBeginInvokeOnUi 方法来更新UI。

代码片段如下:

  1. using GalaSoft.MvvmLight;
  2. using GalaSoft.MvvmLight.Command;
  3. using GalaSoft.MvvmLight.Threading;
  4. using MvvmLightClosableTabControl.Models;
  5. using MvvmLightClosableTabControl.Pages;
  6. using System;
  7. using System.Collections.ObjectModel;
  8. using System.Threading.Tasks;
  9. using System.Windows;
  10. using System.Windows.Input;
  11. using System.Windows.Threading;
  12.  
  13. namespace MvvmLightClosableTabControl.ViewModel
  14. {
  15. public class MainViewModel : ViewModelBase
  16. {
  17. private ObservableCollection<TabItemModel> tabItemsList = new ObservableCollection<TabItemModel>()
  18. {
  19. new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\1.png",Uri="\\Pages\\Page1.xaml",IsSelected=true , Header="TabItem1" },
  20. new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\2.png",Uri="\\Pages\\Page2.xaml",IsSelected=false, Header="TabItem2" },
  21. new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\3.png",Uri="\\Pages\\Page3.xaml",IsSelected=false, Header="TabItem3" },
  22. new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\4.png",Uri="\\Pages\\Page4.xaml",IsSelected=false, Header="TabItem4" },
  23. };
  24.  
  25. public ObservableCollection<TabItemModel> TabItemsList
  26. {
  27. get { return tabItemsList; }
  28. set { tabItemsList = value; RaisePropertyChanged(() => TabItemsList); }
  29. }
  30.  
  31. public MainViewModel()
  32. {
  33. DispatcherHelper.Initialize();
  34. }
  35.  
  36. #region Command
  37.  
  38. private RelayCommand closeCurrentTabItemCommand;
  39.  
  40. public RelayCommand CloseCurrentTabItemCommand
  41. {
  42. get
  43. {
  44. if (closeCurrentTabItemCommand == null)
  45. {
  46. closeCurrentTabItemCommand = new RelayCommand(CloseCurrentTabItemImpl);
  47. }
  48. return closeCurrentTabItemCommand;
  49. }
  50. set { closeCurrentTabItemCommand = value; }
  51. }
  52. private void CloseCurrentTabItemImpl()
  53. {
  54. foreach(var item in TabItemsList)
  55. {
  56. if(item.IsSelected == true)
  57. {
  58. TabItemsList.Remove(item);
  59. break;
  60. }
  61. }
  62.  
  63. }
  64.  
  65. //传递一个字符串参数的命令
  66. private RelayCommand<string> addPageCommand;
  67.  
  68. public RelayCommand<string> AddPageCommand
  69. {
  70. get
  71. {
  72. if (addPageCommand == null)
  73. {
  74. addPageCommand = new RelayCommand<string>(AddPage);
  75. }
  76. return addPageCommand;
  77. }
  78. set { addPageCommand = value; }
  79. }
  80. private void AddPage(string page)
  81. {
  82. try
  83. {
  84. TabItemModel myTabItemModel = new TabItemModel() { Img = $"\\MvvmLightClosableTabControl;component\\Img\\{page[4]}.png", Uri = $"\\Pages\\{page}.xaml", IsSelected = true, Header = page };
  85.   Task.Run( () => DispatcherHelper.CheckBeginInvokeOnUI( () => { TabItemsList.Add(myTabItemModel); } ));//故意在子线程中添加,为了使用DispatcherHelper,在子线程中访问UI
  86. }
  87. catch (AggregateException err)
  88. {
  89. foreach (var iem in err.InnerExceptions)
  90. {
  91. string msg = $"{iem.GetType()}{iem.Source}{iem.Message}";
  92. MessageBox.Show(msg);
  93. }
  94.  
  95. }
  96.  
  97. }
  98.  
  99. //传递事件参数的命令
  100. private RelayCommand<MouseButtonEventArgs> tabItemMouseDoubleClickCommand;
  101.  
  102. public RelayCommand<MouseButtonEventArgs> TabItemMouseDoubleClickCommand
  103. {
  104. get
  105. {
  106. if (tabItemMouseDoubleClickCommand == null)
  107. {
  108. tabItemMouseDoubleClickCommand = new RelayCommand<MouseButtonEventArgs>(TabItemMouseDoubleClickImpl);
  109. }
  110. return tabItemMouseDoubleClickCommand;
  111. }
  112. set { tabItemMouseDoubleClickCommand = value; }
  113. }
  114. private int _clickCnt = 0;
  115. private void TabItemMouseDoubleClickImpl(MouseButtonEventArgs e)
  116. {
  117. _clickCnt += 1;
  118.  
  119. DispatcherTimer timer = new DispatcherTimer();
  120.  
  121. timer.Interval = new TimeSpan(0, 0, 0, 0, 300);
  122.  
  123. timer.Tick += (s, e1) => { timer.IsEnabled = false; _clickCnt = 0; };
  124.  
  125. timer.IsEnabled = true;
  126. if (_clickCnt %2 == 0)
  127. {
  128. foreach (var item in TabItemsList)
  129. {
  130. if (item.IsSelected == true)
  131. {
  132. TabItemsList.Remove(item);
  133. PageWindow win = new PageWindow();
  134. win.frm.Source = new System.Uri(item.Uri, UriKind.Relative);
  135. win.Title = item.Header;
  136. win.Show();
  137. break;
  138. }
  139. }
  140. }
  141. }
  142. #endregion
  143. }
  144. }

MVVMLight学习笔记(六)---DispatchHelper更新UI的更多相关文章

  1. [Android学习笔记]子线程更新UI线程方法之Handler

    关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...

  2. python3.4学习笔记(六) 常用快捷键使用技巧,持续更新

    python3.4学习笔记(六) 常用快捷键使用技巧,持续更新 安装IDLE后鼠标右键点击*.py 文件,可以看到Edit with IDLE 选择这个可以直接打开编辑器.IDLE默认不能显示行号,使 ...

  3. # go微服务框架kratos学习笔记六(kratos 服务发现 discovery)

    目录 go微服务框架kratos学习笔记六(kratos 服务发现 discovery) http api register 服务注册 fetch 获取实例 fetchs 批量获取实例 polls 批 ...

  4. HTML语言学习笔记(会更新)

    # HTML语言学习笔记(会更新) 一个html文件是由一系列的元素和标签组成的. 标签: 1.<html></html> 表示该文件为超文本标记语言(HTML)编写的.成对出 ...

  5. java之jvm学习笔记六-十二(实践写自己的安全管理器)(jar包的代码认证和签名) (实践对jar包的代码签名) (策略文件)(策略和保护域) (访问控制器) (访问控制器的栈校验机制) (jvm基本结构)

    java之jvm学习笔记六(实践写自己的安全管理器) 安全管理器SecurityManager里设计的内容实在是非常的庞大,它的核心方法就是checkPerssiom这个方法里又调用 AccessCo ...

  6. Learning ROS for Robotics Programming Second Edition学习笔记(六) indigo xtion pro live

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...

  7. Typescript 学习笔记六:接口

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  8. Go语言学习笔记六: 循环语句

    Go语言学习笔记六: 循环语句 今天学了一个格式化代码的命令:gofmt -w chapter6.go for循环 for循环有3种形式: for init; condition; increment ...

  9. 【opencv学习笔记六】图像的ROI区域选择与复制

    图像的数据量还是比较大的,对整张图片进行处理会影响我们的处理效率,因此常常只对图像中我们需要的部分进行处理,也就是感兴趣区域ROI.今天我们来看一下如何设置图像的感兴趣区域ROI.以及对ROI区域图像 ...

随机推荐

  1. WIN7 WIN10修改path不用重启即可生效

    近来安装python scrapy经常忘了添加到path,需要时增加了但需要重启才能起作用,用下面的方法马上能生效: 1修改path:右击"计算机"--高级--环境变量--path ...

  2. java网络编程基础——TCP网络编程三

    AIO实现非阻塞通信 java7 NIO2 提供了异步Channel支持,这种异步Channel可以提供更高效的IO,这种基于异步Channel的IO被称为异步IO(Asynchronous IO) ...

  3. 使用vlookup的模糊匹配和字符串拼接

    1,=IF(ISNA(VLOOKUP("*"&$D2&"*",$A$2:$A$43,1,FALSE))=FALSE,TRUE,FALSE) 2, ...

  4. div标签width:auto无效

    1,因为div标签默认是display:block,独占一行,宽度为父元素的100%,但是高度是auto,跟随内部内容而定.所以要想 设值父元素随子元素的宽高,那么就要设置div标签为display: ...

  5. python基础之文件的读取

    #文件名 txt文件的读取#文件的读取 open("文件","读写方法") with open("文件","读写方法") ...

  6. 从源码构建Vim

    从源码构建Vim 引言 事情是介样滴,因为我是个Vim 重度使用者了差不多.. 但在大部分系统上能安装到的或者自带的都是比较老的版本,可能是7.x 之类的.也或者是你需要使用到Vim 的某些特性或者功 ...

  7. 看懂UML类图笔记

    在学习设计模式的时候,经常会遇到UML类图,所以就找了一些资料,做一些笔记. 从一个示例开始 下面这个类图,类之间的关系是我们需要关注的: 车的类图结构为<<abstract>> ...

  8. 【模拟】选数 luogu-1037

    AC代码 #include <bits/stdc++.h> using namespace std; #define ms(a,b) memset(a,b,sizeof(a)) typed ...

  9. 裸奔mysql

    centos 7 下裸奔mysql # vim /etc/my.cnf在[mysqld]的段中加上一句:skip-grant-tables例如:[mysqld]datadir=/var/lib/mys ...

  10. 双击映射坚果云网盘并打开的AHK源代码

    双击映射坚果云网盘并打开的AHK源代码 #SingleInstance,force ;当此脚本已经运行时自动替换旧实例再次运行.#Persistent ;让脚本持久运行(即直到用户关闭或遇到 Exit ...