用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.   
}



原文地址:https://www.cnblogs.com/sparkleDai/p/7605069.html