C# WPF调度程序线程冻结主窗口
而不是在后台工作-此代码仍然冻结我的程序:C# WPF调度程序线程冻结主窗口,c#,wpf,multithreading,task,dispatcher,C#,Wpf,Multithreading,Task,Dispatcher,而不是在后台工作-此代码仍然冻结我的程序: private void button_Click(object sender, RoutedEventArgs e) { this.Dispatcher.BeginInvoke(new Action(() => { Thread.Sleep(5000); label.Content = "Done"; }), DispatcherPriority.Normal); } 我尝试过线程/任务
private void button_Click(object sender, RoutedEventArgs e)
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
我尝试过线程/任务,线程示例:
private void button_Click(object sender, RoutedEventArgs e)
{
var t = new Thread(new ThreadStart(runtask));
t.Start();
}
private void runtask()
{
this.Dispatcher.BeginInvoke(new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}), DispatcherPriority.Normal);
}
任务示例:
private void button_Click(object sender, RoutedEventArgs e)
{
Task.Run(() =>
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
{
Thread.Sleep(5000);
label.Content = "Done";
}));
});
}
但我的程序仍然冻结。有什么建议吗?来自调度程序类的:
提供用于管理线程的工作项队列的服务
从Dispatcher.BeginInvoke的
在创建调度程序的线程上,使用指定的参数异步执行指定的委托
这里“异步”指的是辅助线程,而不是主线程。因为主调度器属于主调度器。这意味着,无论来自哪个线程,对该调度器的Invoke
或BeginInvoke
的每次调用都会将被调用的操作放入主线程必须执行的操作队列中,但从主线程的角度来看,它们将一个接一个地同步执行
例如,如果您放置3个动作,如Thread.Sleep(1000)
在调度程序上的10毫秒内,无论是使用Invoke
还是BeginInvoke
,该调度程序都将使UI线程同步执行3个操作,因此总共需要3000毫秒
也许关于BeginInvoke
的文档可以写得更好,比如:
在创建调度程序的线程上执行具有指定参数的指定委托。从调用线程的角度来看,指定的委托是异步执行的
现在<代码>调用
或开始调用
使用Invoke
,次线程对调度程序说:让我们在主线程上执行此操作,在线程的作业完成之前,不敢返回。只有到那时,我才会继续
例如,如果您编写以下内容:
this.Dispatcher.Invoke(new Action(() =>
{
Thread.Sleep(5000);
Debug.WriteLine("After Sleep");
}));
Debug.WriteLine("Continuation on secondary Thread");
控制台将在约5000毫秒后打印:
“睡后”
“在次线程上继续”
相反,使用BeginInvoke
,线程会说:“嘿,Dispatcher,在主线程上将此操作排队,但请尽快返回,以便我可以立即继续我的工作。”
在这种情况下,控制台将立即打印:
“在次线程上继续”
约5000 ms后:
“睡后”
现在,如果您的目的是在后台执行一些繁重的操作,那么您应该了解异步/等待模式,该模式可从.NET4.5和C#5.0获得
在你的例子中,我会写:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.Delay(5000); // await a heavy operation executed in background
label.Content = "Done"; // control back to the UI Thread that executes this
}
从调度程序
类的
提供用于管理线程的工作项队列的服务
从Dispatcher.BeginInvoke的
在创建调度程序的线程上,使用指定的参数异步执行指定的委托
这里“异步”指的是辅助线程,而不是主线程。因为主调度器属于主调度器。这意味着,无论来自哪个线程,对该调度器的Invoke
或BeginInvoke
的每次调用都会将被调用的操作放入主线程必须执行的操作队列中,但从主线程的角度来看,它们将一个接一个地同步执行
例如,如果您放置3个动作,如Thread.Sleep(1000)
在调度程序上的10毫秒内,无论是使用Invoke
还是BeginInvoke
,该调度程序都将使UI线程同步执行3个操作,因此总共需要3000毫秒
也许关于BeginInvoke
的文档可以写得更好,比如:
在创建调度程序的线程上执行具有指定参数的指定委托。从调用线程的角度来看,指定的委托是异步执行的
现在<代码>调用
或开始调用
使用Invoke
,次线程对调度程序说:让我们在主线程上执行此操作,在线程的作业完成之前,不敢返回。只有到那时,我才会继续
例如,如果您编写以下内容:
this.Dispatcher.Invoke(new Action(() =>
{
Thread.Sleep(5000);
Debug.WriteLine("After Sleep");
}));
Debug.WriteLine("Continuation on secondary Thread");
控制台将在约5000毫秒后打印:
“睡后”
“在次线程上继续”
相反,使用BeginInvoke
,线程会说:“嘿,Dispatcher,在主线程上将此操作排队,但请尽快返回,以便我可以立即继续我的工作。”
在这种情况下,控制台将立即打印:
“在次线程上继续”
约5000 ms后:
“睡后”
现在,如果您的目的是在后台执行一些繁重的操作,那么您应该了解异步/等待模式,该模式可从.NET4.5和C#5.0获得 在你的例子中,我会写:
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.Delay(5000); // await a heavy operation executed in background
label.Content = "Done"; // control back to the UI Thread that executes this
}
如果用户界面访问是方法的最后一步,那么可以使用这个小扩展
如果用户界面访问是方法的最后一步,那么可以使用这个小扩展
是什么让你认为
BeginInvoke
会在后台运行它?从文档中如果您调用Invoke,您实际上处于主线程上。@rhon在文档中表示从调用线程的角度来看它是异步的。从UI线程的角度来看,这绝对是一个同步操作。是的,确切地说……是什么让你认为BeginInvoke
在后台运行它?从文档中如果您调用Invoke,您实际上处于主线程上。@rhon在文档中表示从调用线程的角度来看它是异步的。从UI线程的角度来看,这绝对是一个同步操作。是的,没错……Async/Wait听起来不错,但如果我想更改UI,则需要在代码内部使用dispatcher