用TaskScheduler代替invoke和begininvoke异步更新那界面数据

来源:互联网 发布:战锤全面战争画面优化 编辑:程序博客网 时间:2024/06/14 10:30

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



原创粉丝点击