在我的wpf(c#)应用程序中,当用户按下按钮时会执行一个很长的过程。当按下按钮直到执行完整的代码时,窗口将冻结,用户无法在窗口中执行任何其他任务。如何使按钮单击代码作为后台进程,以便窗口响应用户。我尝试过以下方法,但没有成功。
private void btn_convert_Click(object sender, RoutedEventArgs e)
{
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new Action(() => {
WorkerMethod();
}));
}
其中WorkerMethod是包含整个代码的函数。有什么建议吗
问候,
桑吉塔
如果您的目标是 .NET 4.5,您可以使用
async/await
使您的 UI 响应式:
private async void btn_convert_Click(object sender, RoutedEventArgs e)
{
await WorkerMethod();
}
修改您的
WorkerMethod
:
private Task WorkerMethod()
{
return Task.Run(() =>
{
// your long running task here
});
}
您实际上在这里所做的是要求 UI 线程通过 Dispatcher 运行您的繁重任务。
您应该创建一个新线程/任务并让它运行您的后台方法:
Thread t = new Thread(() => WorkerMethod());
t.Start();
欲了解更多信息,请阅读:
这里答案的替代方案是BackgroundWorker。 它还有一个额外的好处,就是在完成后返回到 GUI 线程。
private void btn_convert_Click(object sender, RoutedEventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += WorkerMethod;
worker.RunWorkerCompleted += WorkerEnded;
worker.RunWorkerAsync();
}
private void WorkerMethod()
{
// New thread, cannot access GUI
}
private void WorkerEnded()
{
// Back on the GUI Thread
// Worker is finished
}
您正在调用
UI-Dispatcher
上的方法,这将使 UI 冻结。使用在您的点击事件中创建一个新线程
private void btn_convert_Click(object sender, RoutedEventArgs e)
{
Thread t = new Thread(new ThreadStart(WorkerMethod));
//assign STA or MTA, etc....
t.Start();
}
查看此处,了解有关“System.Threading.Thread`的信息。
我设想了另一种令我相当自豪的方式: 如果多线程的好处仅在于允许 IHM 为进度条设置动画,如果用户不应该在进程中与 ihm 交互,或者只是没有时间开发多线程并且您不能允许应用程序在没有反馈:
您可以开发一个加载程序,启动到另一个 STA 线程中,该线程创建另一个窗口并在冻结窗口的中间显示此加载程序。
这是我撰写的一篇文章以及此类解决方案的实现:
http://charly-studio.com/blog/a-loader-for-wpf-long-ui-process/
这是我使用组件的方式:
private void MainWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Long UI process context
using (new LongUIProcessContext("Wait while loading..."))
{
Thread.Sleep(2000);
// Sub long ui process context
using (new LongUIProcessContext("Wait while loading 2..."))
{
Thread.Sleep(2000);
}
// Another sub long ui process context
using (new LongUIProcessContext("Wait while loading 3..."))
{
Thread.Sleep(2000);
}
}
}
这是我建议的长凳的样子:
这是我制作的工作台的直接链接,您可以在其中找到组件:
尝试使用Backgroundworker类。您必须注册到 DoWork 事件并创建一个事件处理程序,将所有处理代码放入其中。您可以使用 RunWorkerAsync 方法启动工作线程。还有一种可以报告您的工人进度的方法“ReportProgress”。 RunWorkerCompleted 将在您的工作线程处理完您的代码时向您显示。尝试在网上搜索BackgroundWorker之后,你会发现很多如何使用它的示例
这对我来说效果很好,并且保持 UI 响应:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Render, Sub() Return)