一、概述

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

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

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

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

代码片段如下:

 this.Dispatcher.BeginInvoke((Action)delegate()
{
更新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。

代码片段如下:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Threading;
using MvvmLightClosableTabControl.Models;
using MvvmLightClosableTabControl.Pages;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading; namespace MvvmLightClosableTabControl.ViewModel
{
public class MainViewModel : ViewModelBase
{
private ObservableCollection<TabItemModel> tabItemsList = new ObservableCollection<TabItemModel>()
{
new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\1.png",Uri="\\Pages\\Page1.xaml",IsSelected=true , Header="TabItem1" },
new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\2.png",Uri="\\Pages\\Page2.xaml",IsSelected=false, Header="TabItem2" },
new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\3.png",Uri="\\Pages\\Page3.xaml",IsSelected=false, Header="TabItem3" },
new TabItemModel(){ Img="\\MvvmLightClosableTabControl;component\\Img\\4.png",Uri="\\Pages\\Page4.xaml",IsSelected=false, Header="TabItem4" },
}; public ObservableCollection<TabItemModel> TabItemsList
{
get { return tabItemsList; }
set { tabItemsList = value; RaisePropertyChanged(() => TabItemsList); }
} public MainViewModel()
{
DispatcherHelper.Initialize();
} #region Command private RelayCommand closeCurrentTabItemCommand; public RelayCommand CloseCurrentTabItemCommand
{
get
{
if (closeCurrentTabItemCommand == null)
{
closeCurrentTabItemCommand = new RelayCommand(CloseCurrentTabItemImpl);
}
return closeCurrentTabItemCommand;
}
set { closeCurrentTabItemCommand = value; }
}
private void CloseCurrentTabItemImpl()
{
foreach(var item in TabItemsList)
{
if(item.IsSelected == true)
{
TabItemsList.Remove(item);
break;
}
} } //传递一个字符串参数的命令
private RelayCommand<string> addPageCommand; public RelayCommand<string> AddPageCommand
{
get
{
if (addPageCommand == null)
{
addPageCommand = new RelayCommand<string>(AddPage);
}
return addPageCommand;
}
set { addPageCommand = value; }
}
private void AddPage(string page)
{
try
{
TabItemModel myTabItemModel = new TabItemModel() { Img = $"\\MvvmLightClosableTabControl;component\\Img\\{page[4]}.png", Uri = $"\\Pages\\{page}.xaml", IsSelected = true, Header = page };
  Task.Run( () => DispatcherHelper.CheckBeginInvokeOnUI( () => { TabItemsList.Add(myTabItemModel); } ));//故意在子线程中添加,为了使用DispatcherHelper,在子线程中访问UI
}
catch (AggregateException err)
{
foreach (var iem in err.InnerExceptions)
{
string msg = $"{iem.GetType()}{iem.Source}{iem.Message}";
MessageBox.Show(msg);
} } } //传递事件参数的命令
private RelayCommand<MouseButtonEventArgs> tabItemMouseDoubleClickCommand; public RelayCommand<MouseButtonEventArgs> TabItemMouseDoubleClickCommand
{
get
{
if (tabItemMouseDoubleClickCommand == null)
{
tabItemMouseDoubleClickCommand = new RelayCommand<MouseButtonEventArgs>(TabItemMouseDoubleClickImpl);
}
return tabItemMouseDoubleClickCommand;
}
set { tabItemMouseDoubleClickCommand = value; }
}
private int _clickCnt = 0;
private void TabItemMouseDoubleClickImpl(MouseButtonEventArgs e)
{
_clickCnt += 1; DispatcherTimer timer = new DispatcherTimer(); timer.Interval = new TimeSpan(0, 0, 0, 0, 300); timer.Tick += (s, e1) => { timer.IsEnabled = false; _clickCnt = 0; }; timer.IsEnabled = true;
if (_clickCnt %2 == 0)
{
foreach (var item in TabItemsList)
{
if (item.IsSelected == true)
{
TabItemsList.Remove(item);
PageWindow win = new PageWindow();
win.frm.Source = new System.Uri(item.Uri, UriKind.Relative);
win.Title = item.Header;
win.Show();
break;
}
}
}
}
#endregion
}
}

最新文章

  1. (一)FlexViewer之整体框架解析
  2. Ajax传递路径问题及解决
  3. 升级到win8.1右键响应慢
  4. 利用条件运算符的嵌套来完成此题:学习成绩&gt; =90分的同学用A表示,60-89分之间的用B表示,60分以下的用C表示。
  5. 阻止Application_End事件的解决方案
  6. 设置win7任务栏显示标题,而不显示缩略图
  7. iOS socket小结01
  8. 二、Cocos2dx中Android部分的c++和java实现相互调用(高级篇)
  9. 用OC和Swift一起说说二叉树
  10. css3特效详解
  11. Docker Registry
  12. spring boot2.0.4集成druid,用jmeter并发测试工具调用接口,druid查看监控的结果
  13. ORA-01578 data block corrupted 数据文件损坏 与 修复 (多为借鉴 linux)
  14. 一篇教你看懂spring bean工厂和aop
  15. 【EMV L2】SDA静态数据认证处理流程
  16. PCL数据类型和ROS数据类型的转换
  17. 使用Java代码自定义Ribbon配置
  18. 【未解决】centos 6.4 xen4.2 在关机的时候很慢
  19. 基于9款CSS3鼠标悬停相册预览特效
  20. HTML学习笔记《一》 ---- HTML基本认识

热门文章

  1. [004] - JavaSE面试题(四):JavaSE语法(2)
  2. lucene Hello World
  3. Python+Requests+Bs4(解析)爬取某诗词信息(数据分析二)
  4. session及cookie详解(七)
  5. 图像旋转的FPGA实现(一)
  6. 第4天 JavaDoc生成文档&amp;Java流程控制(第一节:用户交互Scanner)
  7. 算法优化---素数(质数)(Java版)
  8. ts 学习笔记 - 类
  9. ifix 自动化(Automation)错误弹窗的解决方案
  10. C++动态内存管理与源码剖析