首先强调一点:异步更新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界面
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="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界面的详细页面,介绍了和线程,有关的知识,要查看更多相关信息,请点击此处wpf中ui线程队列由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