Task.Factory.StartNew延迟没有ui freez

时间:2016-10-21 22:08:19

标签: c# multithreading

当我在Thread.Sleep程序freez中使用UpdateGuItemsAsync 10秒钟,因为线程被阻止了。如果我在'UpdateGuItemsAsync'中使用Task.Delay,代码会立即执行而不会暂停。我希望在没有UI冻结的列表更新之前得到延迟。如何在.net 3.5中执行此操作?

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(UpdateGuItemsAsync, CancellationToken.None, TaskCreationOptions.None, uiScheduler);


    public void UpdateGuItemsAsync()
    {
        System.Threading.Thread.Sleep(10000);
        for (int i = 0; i < 100; i++)
        {
            Gu45Document gu45Document = new Gu45Document();
            gu45Document.Form = "EU-45";
            Gu45Documents.Add(gu45Document);
        }
    }

4 个答案:

答案 0 :(得分:3)

您可以使用System.Windows.Forms.Timer,等待10秒后不会阻止用户界面:

 public void UpdateGuItemsAsync()
 {
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
    timer.Interval = 10000;
    timer.Tick += (sender, args) => 
    {
        timer.Stop();
        for (int i = 0; i < 100; i++)
        {
            Gu45Document gu45Document = new Gu45Document();
            gu45Document.Form = "EU-45";
            Gu45Documents.Add(gu45Document);
        }
    };
    timer.Start();  
 }

答案 1 :(得分:1)

修改

抱歉,我错过了关于.Net 3.5导致Task.Delay谈话的观点。下面找到.net 3.5中的一个示例,它在10秒后更新表单中的进度条。当按下那种形式的按钮时:

using System;
using System.Threading;
using System.Windows.Forms;

  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    delegate void UpdateGuItemsAsyncDelegate();
    void UpdateGuItemsAsync()
    {
      for (int i = 0; i < 100; i++)
      {
        progressBar1.PerformStep();
      }
    }

    private void button1_Click(object sender, EventArgs e)
    {
      ThreadPool.QueueUserWorkItem(state =>
      {
        Thread.Sleep(10000);

        if (progressBar1.InvokeRequired)
        {
          UpdateGuItemsAsyncDelegate del = new UpdateGuItemsAsyncDelegate(UpdateGuItemsAsync);
          this.Invoke(del);
        }
        else
        {
          UpdateGuItemsAsync();
        }

      });
    }
  }

在WPF / XAML中,如果窗口中有进度条和按钮,则几乎可以执行相同操作:

  <StackPanel>
    <ProgressBar Name="ProgBar" Minimum="0" Maximum="100" Height="20" />
    <Button Name="UpdateCmd" Click="UpdateCmd_Click" Content="Update" />
  </StackPanel>

在代码中:

private void UpdateCmd_Click(object sender, RoutedEventArgs e)
{
  ThreadPool.QueueUserWorkItem(state =>
  {
    Thread.Sleep(10000);

    for (int i = 0; i < 100; i++)
    {
      Dispatcher.Invoke(new Action(() =>
      {
        ProgBar.Value++;
      }));

      Thread.Sleep(50);
    }
  });
}

答案 2 :(得分:1)

在你的情况下,我要做的是使用System.Windows.Threading.DispatcherTimer让它在10秒后运行一个事件。这将适用于WPF和WinForms,但是如果您的项目是winforms,则需要在项目引用中添加对WindowsBase的引用。

private void UpdateGuItemsAsync()
{
    //This line must be called on the UI thread
    var timer = new DispatcherTimer();
    timer.Interval = TimeSpan.FromSeconds(10);
    timer.Tick += OnUpdateGuiItemsTimerTick;
    timer.Start();
}

private void OnUpdateGuiItemsTimerTick(object sender, EventArgs e)
{
    //Stop the timer.
    var timer = sender as DispatcherTimer;
    timer.Stop();

    //Run the code you where waiting for.
    for (int i = 0; i < 100; i++)
    {
        Gu45Document gu45Document = new Gu45Document();
        gu45Document.Form = "EU-45";
        Gu45Documents.Add(gu45Document);
    }
}

下面是一个独立程序,您可以在.NET 3.5中运行以查看它是否有效。您需要做的就是创建一个新的Windows窗体项目,添加对WindowsBase的引用并使用下面的代码

using System;
using System.Windows.Forms;
using System.Windows.Threading;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            UpdateGuiItems();
        }

        private void UpdateGuiItems()
        {
            var timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromSeconds(5);
            timer.Tick += OnUpdateGuiItemsTimerTick;
            timer.Start();
        }

        private void OnUpdateGuiItemsTimerTick(object sender, EventArgs e)
        {
            var timer = sender as DispatcherTimer;
            timer.Stop();

            MessageBox.Show("Am I on the UI thread: " + !this.InvokeRequired);
        }
    }
}

答案 3 :(得分:0)

这应该做的工作

TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew( () => Thread.Sleep( 10000 ) )
    .ContinueWith(
        t => UpdateGuItemsAsync(),
        CancellationToken.None,
        TaskContinuationOptions.None,
        uiScheduler );

public void UpdateGuItemsAsync()
{
    // System.Threading.Thread.Sleep(10000);
    for (int i = 0; i < 100; i++)
    {
        Gu45Document gu45Document = new Gu45Document();
        gu45Document.Form = "EU-45";
        Gu45Documents.Add(gu45Document);
    }
}

我正在使用NuGet包Task Parallel Library for .NET 3.5