Task.Factory.StartNew延迟没有ui冻结

本文关键字:ui 冻结 延迟 Factory StartNew Task | 更新日期: 2023-09-27 18:14:10

当我使用Thread.SleepUpdateGuItemsAsync程序冻结10秒,因为线程被阻塞。如果我使用Task.Delay在'UpdateGuItemsAsync'代码立即执行没有暂停。我希望在没有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);
        }
    }

Task.Factory.StartNew延迟没有ui冻结

你可以使用System.Windows.Forms.Timer,它不会在等待10秒时阻塞UI:

 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();  
 }

在您的情况下,我要做的是使用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);
        }
    }
}

EDIT

对不起,我错过了关于。net 3.5导致任务的要点。推迟讨论。下面是。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);
    }
  });
}

应该可以了

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);
    }
}

我正在使用。net 3.5的NuGet包任务并行库。