如何阻止BackgroundWorker阻止UI线程?

时间:2015-08-27 06:32:32

标签: c# wpf multithreading

在我的XML编辑器中,我希望能够使用索引文件一次打开多个文件。显然,根据文件的数量,这可能需要一些时间,我想使用进度条通知用户程序仍在加载并执行某些操作。 根据我的研究,保持UI进度条更新的方法是使用BackgroundWorker。

public MainWindow()
        {
            InitializeComponent();

            tabList = new ObservableCollection<FileTab>();

            tabControl.ItemsSource = tabList;

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += backgroundWorker_DoWork;
            backgroundWorker.ProgressChanged += backgroundWorker_ProgressChanged;
            backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
            backgroundWorker.WorkerReportsProgress = true; 
        }

(...)

private void OpenProjectButtonClick(object sender, RoutedEventArgs e) 
        {
            openingProgressBar.Value = 0;
            openingProgressBar.Visibility = System.Windows.Visibility.Visible;
            backgroundWorker.RunWorkerAsync();
        }

void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            int i = 0;
            foreach (IndexFile file in indexManager.fileList)
            {
                this.Dispatcher.Invoke((Action)(() =>
                    {
                        tabList.Add(new FileTab(file.filePath));
                    }));
                i++;
                Console.WriteLine("-(DoWork)->" + i);
                double percentage = (Convert.ToDouble(i) / Convert.ToDouble(indexManager.fileList.Count)) * 100;
                Console.WriteLine("-(DoWork.percentage)-> "+ percentage);
                backgroundWorker.ReportProgress((int)percentage);
            }
        }
void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            openingProgressBar.Value = e.ProgressPercentage;
            Console.WriteLine("-(ProgressChanged)->" + openingProgressBar.Value);
        }
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            openingProgressBar.Visibility = System.Windows.Visibility.Collapsed;
            backgroundWorker.Dispose();
            Console.WriteLine("-(RunWorkerComplete)-> Done");
        }

由于我正在访问DoWork-Method中的tablist,因此我将该调用包装在Dispathcer.Invoke中。在这种形式的代码类型做我想要的。它使折叠的progressBar可见,并且每隔一段时间更新一次。可悲的是,它并没有在每个文件加载后更新百分比。从我在控制台中看到的情况来看,ProgressChanged执行落后于DoWork。根据我的理解,它在循环的每次迭代中都被调用。即使它触发了UI,也不会总是回应它。

所以我的问题是:我是否仍以某种方式阻止UI线程,我该如何解决?

1 个答案:

答案 0 :(得分:0)

尝试将报告进度操作移动到调度程序的操作中:

 foreach (IndexFile file in indexManager.fileList)
            {
                this.Dispatcher.Invoke((Action)(() =>
                    {
                        tabList.Add(new FileTab(file.filePath));
                        Console.WriteLine("-(DoWork)->" + i);
                        double percentage = (Convert.ToDouble(i) / Convert.ToDouble(indexManager.fileList.Count)) * 100;
                        Console.WriteLine("-(DoWork.percentage)-> "+ percentage);
                        backgroundWorker.ReportProgress((int)percentage);
                    }));
                i++;

            }

调度员可能在另一个线程中运行......