WPF:后台线程更新UI的问题

3

我的代码启动了一个后台线程。后台线程进行更改,并希望主线程中的UI进行更新。启动线程的代码如下所示:

                Thread fThread = new Thread(new ThreadStart(PerformSync));

                fThread.IsBackground = true;
                fThread.Start();

                fThread.Join();

                MessageBox.Show("Synchronization complete");

当后台想要更新UI时,它会设置一个StatusMessage并调用以下代码:

    static StatusMessage _statusMessage;
    public delegate void AddStatusDelegate();
    private void AddStatus()
    {
        AddStatusDelegate methodForUIThread = delegate
        {
            _statusMessageList.Add(_statusMessage);
        };

        this.Dispatcher.BeginInvoke(methodForUIThread, System.Windows.Threading.DispatcherPriority.Send);
    }

_statusMessageList是一个ObservableCollection,它是ListBox的数据源。

调用AddStatus方法,但主线程上的代码从未执行——也就是说,在线程执行时,_statusMessage没有添加到_statusMessageList中。然而,一旦完成(fThread.Join()返回),主线程上积累的所有调用都会被执行。

但是,如果在调用fThread.Start()和fThread.Join()之间显示一个消息框,则状态消息将被正确更新。

我需要做什么更改,以便在等待线程终止时,主线程中的代码(UI更新)执行?

谢谢。

3个回答

6

fThread.Join 会导致您的主线程阻塞,直到后台线程完成。只要主线程被阻塞,UI 就无法更新。

您需要做的是类似于以下内容(未经测试,但您应该能够理解):

void someUiEventThatCausesTheBackgroundProcessingToStart() {
    Thread fThread = new Thread(new ThreadStart(PerformSync));
    fThread.IsBackground = true;

    // disable some UI components here, so that the user cannot
    // start the thread a second time
    ...

    fThread.Start();

    // *don't* call Thread.Join here, so that your main thread does not block!
}

void PerformSync() {
    try {
        // do your stuff here
        ...
    } finally {
        Dispatcher.Invoke(new Action(ProcessingDone));
    }
}

void ProcessingDone() {
    // re-enable the UI components
    ...

    MessageBox.Show("Synchronization complete");
}

当然,在WPF中,禁用/启用UI组件最好使用一些与触发器绑定的IsBusyProcessing依赖属性来完成,但这是另一个故事...
编辑:作为另一个选择,你可能想要查看包含ProgressChangedRunWorkerCompleted事件的BackgroundWorker类,这些事件会自动在主线程中触发。

4
fThread.IsBackground = true;
fThread.Start();

fThread.Join();

调用Join()会阻塞主线程,直到后台线程完成。因此,当另一个线程正在运行时,UI线程无法执行任何操作。您需要避免调用Join()。如果需要在后台线程完成后在主线程上执行某些操作,请寻找其他方法。

编辑:如果在调用Start和Join之间显示消息框,则它能正常工作,因为主线程正在运行消息框的消息循环,而不是被阻塞在Join调用处。


1

BackgroundWorker 是处理这项任务的合适工具。它并不比必要复杂,提供了所有你需要的进度报告钩子,而且有很多信息可用(例如 this answer),教你如何使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接