感谢[Jason_Yuan]原文来源于:[https://www.jianshu.com/p/0714fc755988]
个人浅知,用自己能看懂 的写一下,如有错误,请指教!谢谢!
对Dispatcher认知
首先,我们要对WPF应用中程序开启的时候是开启了一个进程,进程中至少两个线程:
一个线程用于呈现UI,隐藏于后台。
一个线程用于接受输入、处理事件等。即为UI线程。
而在UI线程中有一个Dispatcher对象,该对象的作用在于管理UI线程每个执行的工作项。根据每个工作的优先级排队,优先级可设置,有十个不同级别。Dispatcher队列工作项应保证小,保证个用户体验。
Dispatcher提供了两个注册工作项的方法:Invoke 和 BeginInvoke。
Invoke方法:这是个同步调用,就是要执行完这个注册对的工作项(执行完委托)才会返回。
BeginInvoke方法:这是个异步调用,即可返回。
解决的问题
我们在设计程序的的过程中总会涉及到某些耗时操作会占用主线程,造成程序假死,用户体验差,这种问题我们就要用到子线程去处理耗时操作,而子线程不能直接修改主线程(UI线程)创建的UI对象,必须通过向UI线程中的Dispatcher注册工作项来完成。如下例子中,我需要创建一个子线程去执行加载ProgressBar的操作,这是个耗时操作,如果置于主线程,则会造成假死。所以,我们需要子线程执行耗时操作。
例子代码
XAML
<Window x:Class="About_DispatherClass.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:About_DispatherClass"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="300">
<StackPanel>
<ProgressBar Name="schduleBar" Height="30" Width="250" Margin="20"></ProgressBar>
<TextBox Name="scheduleNum" Height="20" Width="30" HorizontalAlignment="Center">0</TextBox>
<Button Name="btnStart" Content="Start" Height="30" Width="100" Margin="10"></Button>
<Button Name="btnCancel" Content="Cancel" Height="30" Width="100"></Button>
</StackPanel>
</Window>
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace About_DispatherClass
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
btnStart.Click += BtnStart_Click;//注册按钮事件
btnCancel.Click += BtnCancel_Click;
}
Thread threadStart;//声明线程
/// <summary>
/// 开始进度按钮事件
/// </summary>
private void BtnStart_Click(object sender, RoutedEventArgs e)
{
threadStart = new Thread(DoTask);//创建线程,去更新加载进度条信息及加载数具体数字
threadStart.Start();
/////////////////////////////////////////////
//关闭线程。如果这样,程序则会假死
//int maxValue = 100;
//for (int i = 0; i < maxValue; i++)
//{
// Thread.Sleep(100);//线程休眠 100ms
// this.Dispatcher.BeginInvoke((Action)delegate ()//向Dispatcher里注册工作方法
// {
// this.schduleBar.Value = i;
// this.scheduleNum.Text = i.ToString();
// });
//}
/////////////////////////////////////////////////
}
/// <summary>
/// 取消进度按钮事件,恢复默认
/// </summary>
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
threadStart.Abort();//终止线程
MessageBox.Show("取消加载,恢复默认", "提示");
this.schduleBar.Value = 0;//清空
this.scheduleNum.Text = null;
}
/// <summary>
/// 新线程要做的事情,完成加载进度条,
/// </summary>
private void DoTask()
{
int maxValue = 100;
for (int i = 0; i < maxValue; i++)
{
Thread.Sleep(100);//线程休眠 100ms
this.Dispatcher.BeginInvoke((Action)delegate()//向Dispatcher里注册工作方法
{
this.schduleBar.Value = i;
this.scheduleNum.Text = i.ToString();
});
}
MessageBox.Show("加载完成,恢复默认","提示");
this.Dispatcher.BeginInvoke((Action)delegate
{
this.schduleBar.Value = 0;
this.scheduleNum.Text = null;
});
}
}
}
展示


网友评论