zoukankan      html  css  js  c++  java
  • 【转】WPF 异步执行方法后对 UI 进行更新的几种方法

    使用 async/await 的情况:

    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        (sender as Button).IsEnabled = false;
        const string do7zCmd = @"a D:x7zaTest.7z"
            + @" E:WpfApp1WpfApp1inDebug*.dll"
            + @" E:WpfApp1WpfApp1inDebug*.xml"
            ;
    
        tex1.Text = "Running...";
        tex1.Focus();
    
        var ret = await Task.Run(() => X7za.Do7z(do7zCmd));
    
        //更新UI线程的操作
        tex1.Text += "
    " + ret + "
    " + do7zCmd;
        (sender as Button).IsEnabled = true;
    }

    在不使用 async/await 的情况下有 3 种办法:

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        (sender as Button).IsEnabled = false;
        const string do7zCmd = @"a D:x7zaTest.7z"
            + @" E:WpfApp1WpfApp1inDebug*.dll"
            + @" E:WpfApp1WpfApp1inDebug*.xml"
            ;
    
        //更新UI线程的操作
        var f = new Action<int>(ret =>
        {
            tex1.Text += "
    " + ret + "
    " + do7zCmd;
            (sender as Button).IsEnabled = true;
        });
    
        //1.BackgroundWorker - 推荐,有进度报告机制,对 UI 的操作在创建线程内
        var b = new BackgroundWorker();
        b.DoWork += (o, args) => args.Result = X7za.Do7z(do7zCmd);
        b.RunWorkerCompleted += (o, args) => f((int)args.Result);
        b.RunWorkerAsync();
    
        //2.委托异步执行 - 主要就是下面的 BeginInvoke 调用,
        //这是从 BackgroundWorker 的源码里挖出来的用法。
        //
        //这个片段对 UI 线程的操作是在别的线程通过 WPF
        //Application 对象的 Dispatcher 机制跨线程执行的。
        new Action(() =>
        {
            var ret = X7za.Do7z(do7zCmd);
            Application.Current.Dispatcher.Invoke(() => f(ret));
        }).BeginInvoke(null, null);
    
        //3.Task.Run - 很通俗的方法了。对 UI 的操作跟片段2一样。
        Task.Run(() =>
        {
            var ret = X7za.Do7z(do7zCmd);
            Application.Current.Dispatcher.Invoke(() => f(ret));
        });
    
        tex1.Text = "Running...";
        tex1.Focus();
    }

    就是酱紫。
    推荐第一种,WinForm 程序也可以用。

    WPF异步更新UI的两种方法

     首先强调一点:异步更新UI实际上就是新开一个线程,执行耗时的任务,但是UI上的东西又不能被其他线程访问,所以非UI线程分析UI的那几条代码用一种特殊的方法来执行,从而实现既可以将耗时的操作放在其他线程,有可以更新UI。 

    1、方法一
    案例:UI上有三个TextBlock,一个Button,当点击button的时候新三个task产生随机数(模拟耗时操作),然后将产生的随机数给UI显示

            private void Button_Click(object sender, RoutedEventArgs e)
            {
            //也可以Task task = new Task(SchedulerWork);task .Start()
                Task.Factory.StartNew(SchedulerWork);
            }               
    
            private void SchedulerWork()
            {
            //fistr,second,three是三个TextBlock控件的名字
                Task task = new Task((tb) => Begin(this.first), this.first);
                Task task2 = new Task((tb) => Begin(this.second), this.first);
                Task task3 = new Task((tb) => Begin(this.Three), this.first);
                task.Start();
                task2.Start();
                task3.Start();
                Task.WaitAll(task, task2, task3);
            }
    
            private void Begin(TextBlock tb)
            {
                int i = 100000000;
                while (i > 0)
                {
                    i--;
                }
                Random random = new Random();
                String Num = random.Next(0, 100).ToString();
                this.Dispatcher.BeginInvoke(new Action(() => tb.Text = Num));
              }           

    主要注意的几点:
    1、Begin方法不是在UI线程上执行的,所以他里面不能访问UI上的元素,也就是不能执行tb.Text = Num,否则他就是会报异常:(A first chance exception of type ‘System.InvalidOperationException’ occurred in WindowsBase.dll
    Additional information: The calling thread cannot access this object because a different thread owns it.)
    2、因此我们更新UI的部分采用:
    this.Dispatcher.BeginInvoke(new Action(() => tb.Text = Num));
    方法来进行更新,这样实际上就交给UI线程来做了,也就不会报错了。
    2 方法二 
    直接上代码

            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Task.Factory.StartNew(SchedulerWork);
            }
    
            private readonly TaskScheduler _syncContextTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
    
            private void SchedulerWork()
            {
                Task task = new Task((tb) => Begin(this.first), this.first);
                Task task2 = new Task((tb) => Begin(this.second), this.first);
                Task task3 = new Task((tb) => Begin(this.Three), this.first);
                task.Start();
                task2.Start();
                task3.Start();
                Task.WaitAll(task, task2, task3);
            }
    
            private void Begin(TextBlock tb)
            {
                int i = 100000000;
                while (i > 0)
                {
                    i--;
                }
                Random random = new Random();
                String Num = random.Next(0, 100).ToString();
                Task.Factory.StartNew(() => tb.Text = Num, new CancellationTokenSource().Token, TaskCreationOptions.None, _syncContextTaskScheduler).Wait();
            }
  • 相关阅读:
    C#搭建Oauth2.0认证流程以及代码示例
    DirectoryEntry配置IIS7出现ADSI Error:未知错误(0x80005000)
    C# 操作IIS方法集合
    dedecms首页入口的详细注释
    分享几个在线生成网址二维码的API接口
    Windows平台分布式架构实践
    WINDOWS 2008Server 配置nginx 反向代理服务器 安装成服务
    [支付宝]手机网站支付快速接入
    支付宝 app支付 沙盘使用
    支付宝接口开发-手机网站支付-沙箱测试
  • 原文地址:https://www.cnblogs.com/chriskwok/p/11434075.html
Copyright © 2011-2022 走看看