我创建了一个简单的WPF应用程序,并在默认窗口中添加了一个按钮。当我点击按钮时,会调用一个模拟的长工作方法(使用Thread.Sleep(15000)进行模拟)。我试图让按钮异步执行,但是尽管有以下在线示例,按钮和整个窗口会立即锁定单击并保持不变,直到Thread.Sleep(...)结束。
为什么会发生这种情况?
以下是代码:
private void button1_Click(object sender, RoutedEventArgs e)
{
DoSomeAsyncWork();
}
private void DoSomeAsyncWork()
{
System.Windows.Threading.Dispatcher.Run();
Thread thread = new System.Threading.Thread(
new System.Threading.ThreadStart(
delegate()
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => Thread.Sleep(15000)));
}
));
thread.Start();
}
答案 0 :(得分:13)
您将长操作放回UI线程中。让我评论你的例子:
Thread thread = new System.Threading.Thread(
new System.Threading.ThreadStart(
delegate() {
// here we are in the background thread
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(() => {
// here we are back in the UI thread
Thread.Sleep(15000);
}));
}
));
所以,你应该像这样修改你的例子:
Thread thread = new System.Threading.Thread(
new System.Threading.ThreadStart(
delegate() {
// here we are in the background thread
Thread.Sleep(15000); // <-- do the long operation here
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new Action(() => {
// here we are back in the UI thread
// do stuff here that needs to update the UI after the operation finished
}));
}
));
正如其他人所提到的,使用BackgroundWorker类更容易。这是一个例子:
private void DoSomeAsyncWork()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (sender, args) => {
// do your lengthy stuff here -- this will happen in a separate thread
Thread.Sleep(15000);
}
bw.RunWorkerCompleted += (sender, args) => {
if (args.Error != null) // if an exception occurred during DoWork,
MessageBox.Show(args.Error.ToString()); // do your error handling here
// do any UI stuff after the long operation here
...
}
bw.RunWorkerAsync(); // start the background worker
}
答案 1 :(得分:3)
通过使用BeginInvoke
,您实际上是在UI线程上执行代码。
您只需在从后台工作线程更新UI时使用此功能。如果您只是:
Thread thread = new System.Threading.Thread(
new System.Threading.ThreadStart(
delegate()
{
Thread.Sleep(15000);
}
));
我认为它会奏效。
但是,您没有提出“已完成工作”事件,因此您无法知道线程何时(或确实如此)已完成。查看BackgroundWorker
class。这对你来说很重要。您只需将代码插入DoWork
方法。
答案 2 :(得分:1)