WPF多线程UI锁定



我正在尝试创建一个加载窗口,该窗口将有一个进度条,并在后台工作人员进行一些时间密集型工作时显示该进度条。不幸的是,这个加载窗口只是部分加载,然后冻结,直到后台工作完成。如何修复此问题,使加载窗口不会与后台进程冲突?

视觉示例:https://i.stack.imgur.com/JHXvv.png


        lw = new LoadWindow();
        lw.Show();            
        worker.DoWork += delegate(object s, DoWorkEventArgs args)
        {
            /*Program-specific code*/
            string theDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); /* get the folder location of the exe */
            string filePath = theDirectory + "\export.xml";
            if (!File.Exists(filePath))
            {
                FileStream f = File.Create(filePath);
                f.Close();
            }
            FileStream fileStream = File.Open(filePath, FileMode.Open);
            fileStream.SetLength(0);
            fileStream.Close();
            FileStream fsWrite = File.Open(filePath, FileMode.Open, FileAccess.Write, FileShare.None);
            StreamWriter sw = new StreamWriter(fsWrite);
            Dispatcher.Invoke(new Action(delegate() { 
                /*Program-specific code*/                    
                System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("cmd.exe", "/C svn log " + FolderPath.Text + " -v --xml");
                startInfo.CreateNoWindow = true;
                startInfo.RedirectStandardOutput = true;
                startInfo.UseShellExecute = false;
                using (System.Diagnostics.Process process = Process.Start(startInfo))
                {
                    using (StreamReader reader = process.StandardOutput)
                    {
                        string outStr = reader.ReadToEnd();
                        sw.Write(outStr);
                        sw.Close();
                        fsWrite.Close();
                        reader.Close();
                        process.WaitForExit();
                    }
                }
                TicketIDChanged(sender, new TextChangedEventArgs(e.RoutedEvent, new UndoAction()));
            }), DispatcherPriority.Background);             
        };
        worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
        {
            lw.Hide();
        };
        worker.RunWorkerAsync();

通过使用Dispatcher.Invoke(),您将委托中的所有工作委托到UI线程上。如果这是一次耗时的手术,它会被困在这里。

请尝试仅将Dispatcher.Invoke()用于更新UI状态。如果这不容易访问,请尝试重构代码并添加多个调用。

您还可以设置worker.WorkerReportsProgress = true并使用worker.ReportProgress(int percent, object args)方法更新加载屏幕上的简单进度条。调度将由BackgroundWorker处理。

例如,尝试只调用TickedIDChanged-方法。

您正在使用Dispatcher.Invoke()在GUI线程上运行一大块代码(从StartProcess到WaitForExit)。是的,那会挡住的。

我看不出调用的原因。运行进程非常适合在DoWork()中运行。

唯一需要同步的部分是最后的TicketIDChanged()。对Dispatcher.Invoke()执行此操作或将其移动到Completed事件。

看起来您是在UI线程上而不是在后台执行工作。我可能错了,因为我不能100%确定后台优先级的含义。然而,我建议您不要在调度程序调用中进行异步工作。。。如果异步工作的一部分是分配给UI线程上的某个东西,那么只在已完成的处理程序内的调度器调用中进行分配,并像您所做的那样隐藏。

随着.NET 4.0的发布,我们得到了任务并行库(TPL),它提供了用于执行并行和基于任务的异步操作的API。TPL提供了Task和Parallel这样的类,它们分别用于执行异步编程和并行操作。在带有C#5.0的.NET 4.5中,我们获得了用于表示异步方法的async和wait关键字。在WPF中,我们可以使用Task类来创建响应式和交互式应用程序。

最新更新