用TaskScheduler代替invoke和begininvoke异步更新那界面数据
在异步编程时,为了更新界面的数据,经常会用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.
}

浙公网安备 33010602011771号