1

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

一个视觉示例:http: //i.imgur.com/1jQszPt.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();
4

4 回答 4

1

By using Dispatcher.Invoke() you are delegating all the work within the delegate onto the UI-Thread. If this is a time intensive operation it'll get stuck here.

Try to use Dispatcher.Invoke() for updating UI states only. If this isn't easily accessible, try to refactor your code and add multiple invocations.

You can also set worker.WorkerReportsProgress = true and use the worker.ReportProgress(int percent, object args) method to update a simple progress bar on your loading screen. The dispatching will then be handled by the BackgroundWorker.

Try to invoke only the TickedIDChanged-method, for example.

于 2013-07-15T21:20:37.893 回答
1

Dispatcher.Invoke()用于在 GUI 线程上运行大量代码(从 StartProcess 到 WaitForExit)。是的,那会阻塞。

而且我看不到调用的原因。运行进程非常适合在DoWork().

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

于 2013-07-15T21:24:32.340 回答
0

看起来您正在 UI 线程而不是背景上进行工作。我可能错了,因为我不能 100% 确定背景优先级的含义。但是,我建议您尝试的是不要在调度程序调用中执行异步工作...如果异步工作的一部分是分配给 UI 线程上的某些内容,那么只需在已完成的调度程序调用中执行分配处理程序和你一样的隐藏。

于 2013-07-15T21:14:29.367 回答
0

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

于 2016-03-26T18:31:46.700 回答