当前位置: 首页 > 工具软件 > dispatcher > 使用案例 >

C#中关于Dispatcher中Invoke和BeginInvoke的总结

太叔烨霖
2023-12-01

前言

WPF(Framework框架)中关于Dispatcher的总结

一、对于线程的理解

首先,对于WPF应用程序,用于接受输入、处理事件的线程成为UI线程,在UI线程中有一个DIspatcher对象(this.Dispatcher),该对象的作用在于管理UI线程每个执行的工作项,根据每个工作的优先级排队,优先级可以设置。

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

Invoke方法:这个是同步调用,就是要执行完这个注册的工作项(执行委托)才会返回

BeginInvoke方法: 这是个异步调用,即可返回

二、解决问题

我们在设计程序的时候会涉及到某些耗时操作会占用主线程,早成程序卡假死,用户体验感差,这种问题我们就要用到子线程去处理耗时操作,而子线程不能直接修改主线程(UI线程)中创建的对象,必须通过向UI线程中的Dispatcher注册工作项来完成。
        例:加载进度条,耗时操作,放在子线程中进行操作

三、项目代码

<Window x:Class="DispatcherTest.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:DispatcherTest"
        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>
 public MainWindow()
        {
            InitializeComponent();
            this.btnStart.Click += BtnStart_Click;
            this.btnCancel.Click += BtnCancel_Click;
        }

        Thread threadStart; //声明线程
        private void BtnStart_Click(object sender, RoutedEventArgs e)
        {
            threadStart = new Thread(DoTask); //创建线程,去更新加载进度条信息及加载数具体数字
            threadStart.Start();
        }
        private void DoTask()
        {
            int maxValue = 100;
            for(int i =0; i<maxValue; i++)
            {
                Thread.Sleep(100);
                this.Dispatcher.BeginInvoke((Action)delegate () //向Dispatcher里注册工作方法
                {
                    this.schduleBar.Value = i;
                    this.scheduleNum.Text = i.ToString();
                });
            }

            this.Dispatcher.Invoke((Action)delegate () //从子线程又回到主线程
            {
                MessageBox.Show("加载完成");        //主线程弹窗,必须关掉MessageBox才能后续操作
            });
        }
        private void BtnCancel_Click(object sender, RoutedEventArgs e)
        {
            threadStart.Abort();    //中止线程
            MessageBox.Show("取消加载,恢复默认","提示");
            this.schduleBar.Value = 0;
            this.scheduleNum.Text = null;
        }

其中,在线程中的委托事件DoTask()中是在开启子线程中操作的,

this.Dispatcher.Invoke((Action)delegate ()
{
    MessageBox.Show("加载完成");        //主线程弹窗,必须关掉MessageBox才能后续操作
});

this.Dispatcher.Invoke((Action)delegate (),又回到主线程的同步调用,(必须关闭掉MessageBox才能回到主线程),才能点Cancel按钮/拖动主界面;

若代码改为异步调用, this.Dispatcher.BeginInvoke((Action)delegate ()

this.Dispatcher.BeginInvoke((Action)delegate ()
{
    MessageBox.Show("加载完成");        //主线程弹窗,必须关掉MessageBox才能后续操作
});

则可以点击Cancel按钮/拖动主界面;

四、总结

Invoke方法:这个是同步调用,就是要执行完这个注册的工作项(执行委托)才会返回

BeginInvoke方法: 这是个异步调用,即可返回


 

 类似资料: