添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

首先强调一点:异步更新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();

下一篇讲讲CancellationTokenSource的作用

C#实现窗体加载进度条或者百分比实时显示耗时操作的进度,方法有很多。但是经过我的学习、查找与实际应用,发现Task配合MethodInvoker最为高效便捷。下面我就来结合代码讲一下要注意的问题。 在以往的 VB6,或者是 Windows Form 應用程式更新 UI的方式極為簡單,往往只是 Application.DoEvents 就可以更新。Windows Form 更有 Invoke 與 BeginInvoke 可以彈性地使用。 那在 WPF ,要如何更新 UI 的內容呢? XAML界面 &amp;lt;Window xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot; xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xam... 在UI定义一个TextBox和一个Button 测试异步函数更新UI。<TextBox x:Name="txtSN" Margin="2" VerticalAlignment="Center"></TextBox> <Button x:Name="btnUpdateSn" Margin="2" VerticalAlignment="Center" Click="btnUpdateSn_Click">UpdateSN</Button>定义一个异步函数: 首先强调一点:异步更新 UI 实际上就是新开一个线程,然后线程执行一些耗时的任务,而 UI 线程继续响应用户的操作。 但是 WPF 的机制确限制新开的线程不能直接访问 UI 控件,所以 非UI线程 访问 UI 控件就需要用一种特殊的方法来执行。 ▪ 使用 Task 类异步更新 环境:Task 类需要 .Net 4.0 以上 案例:UI 上有三个 TextBlock,一个 Button 逻辑:当点击 Button 的时候新三个 Task 产生随机数(模拟耗时操作),然后将产生的随机数给UI显示 Private Sub FTest() ...数据处理 System.Windows.Application.Current.Dispatcher.Invoke(New Action(AddressOf 主线程更新UI的函数)) ...数据处理 End Sub 在做WPF开发时,如果直接在子线程更新UI会报错—–“调用线程无法访问此对象,因为另一个线程拥有该对象。”,这是因为WPF禁止在非UI线程里直接更新UI界面。 解决方案:   在子线程里调用Dispatcher.BeginInvoke()或者Invoke()方法。   例如更新一个Button上的文字内容,可以在子线程里这样写: this.myButton.Dispatcher.BeginInvoke(new Action(()=> this.myButton.Content ... 在wpf的用户线程更新ui界面作者: maco 和线程相关 20071124<br />简介:这是在wpf的用户线程更新ui界面的详细页面,介绍了和线程,有关的知识,要查看更多相关信息,请点击此处wpfui线程队列由dispatcher来管理和调度,所以当用户线程更新ui时,必须通过dispatche来调度,下面这个小例子将给用户展示如何在用户线程更新当前的时间.<br /> <br />前台的xaml代码如下:<br /><windowx:class="threadinvoke.window1" 常见的问题"调用线程无法访问此对象,因为另一个线程拥有该对象。" 常见错误测试代码如下: private void UpdateWrongMethod()  {           try            {                Thread.Sleep(100 WPF框架规定只有UI线程(主线程)可以更新界面,所有其他后台线程无法直接更新界面。幸好,WPF提供的SynchronizationContext类以及C#的Lambda表达式提供了一种方便的解决方法。以下是代码: public static SynchronizationContext s_SC = Synchronization.Current; //主窗口类的静态成员 在App类... WPF 使用Task更新UI 有时候,我们需要操作比较耗时的操作,但又不想界面出现假死现象来等待我们的操作,我们可以使用一些遮罩层动画,在进行耗时的操作时,用一些加载动画来规避界面假死; Task task = new Task(() => //开启加载动画跨线程更新UI(myAnimation指遮罩层动画) this.Dispatcher.Invoke(() => { 这是一个普遍的问题:如果我们再程序使用了多线程技术,而工作线程(后台线程)如果需要更新界面上的元素(例如进度条等),就会有一个线程安全性问题,因为进度条是由主线程创建出来的。 关于这一点,大致上看,WPF的机制与Windows Forms是没有差别的。我们在Windows Forms需要按照下面的方式更新窗体元素。 using System; using System.Windows.Forms; using System.Threading; namespace WindowsFormsA