在异步编程时,为了更新界面的数据,经常会用invoke和begininvoke来操作。而这两个方法又必须是基于控件的,所以为了能够调用还必须传一个控件进去。而在基于任务编程时,可以使用TaskScheduler来直接更新数据。下面是代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading.Tasks; using System.Threading; using System.Collections.Concurrent; namespace UpdateUIData { public partial class FormMain : Form { public FormMain() { InitializeComponent(); } Task<string> generateDataTask = null; private void buttonStart_Click(object sender, EventArgs e) { generateData(); updateUI(); } private void generateData() { int count = 1000; generateDataTask = Task.Factory.StartNew(() => { var data = new StringBuilder(); while (count > 0) { data.Append(count.ToString()).Append(","); count--; } return data.ToString(); }); } private void updateUI() { var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); var updateUITask = generateDataTask.ContinueWith((t) => { textBoxData.Text = t.Result; }, uiScheduler); } } }
由generateData开启一个任务生成数据,再由updateUI开启一个任务去更新UI数据。这里关键是用到了TaskScheduler.FromCurrentSynchronizationContext()来获取当前上下文的任务调度,然后利用它来来实现任务间对界面数据的更新。
这样也就避免了invoke和begininvoke的使用。当然如果想要将生成的数据直接更新到界面也是可以的,下面是代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Threading.Tasks; using System.Threading; using System.Collections.Concurrent; namespace UpdateUIData { public partial class FormMain : Form { public FormMain() { InitializeComponent(); } Task<string> generateDataTask = null; private void buttonStart_Click(object sender, EventArgs e) { // generateData(); // updateUI(); generateDataToUI(); } private void generateDataToUI() { int count = 1000; var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); Task.Factory.StartNew(() => { while (count > 0) { textBoxData.Text += count.ToString() + ","; count--; } }, CancellationToken.None, TaskCreationOptions.None, uiScheduler); }
不过,由于数据是异步更新的,所以界面上的显示会滞后。
如果数据更新很卡或者更新失败,可能需要在类的构造方法或者From加载时加入设置同步上下文的代码,比如
private void FormMain_Load(object sender, EventArgs e) { SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());//If not set,update ui will be exception. }或者
public MyClass() { SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());//If not set,update ui will be exception. }