Task.Factory.StartNew延迟没有ui冻结
本文关键字:ui 冻结 延迟 Factory StartNew Task | 更新日期: 2023-09-27 18:14:10
当我使用Thread.Sleep
在UpdateGuItemsAsync
程序冻结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);
}
}
你可以使用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包任务并行库。