C#,MVVM,任务和UI线程

Chr*_*ris 5 c# wpf multithreading task mvvm

我们有一个根据MVVM模式构建的应用程序.在不同的时间,我们启动任务以转到数据库以检索数据,然后我们填充一个ObservableCollection,WPF控件与该数据绑定到该ObservableCollection.

我们有点困惑,当我们在任务线程而不是UI线程上填充ObservableCollection时,UI仍然正在更新/正常运行.我们期待一个错误,并且必须更改代码以填充UI线程上的集合.

这是一个危险的场景吗?我们应该填充UI线程吗?

获取数据的代码:

Task.Factory.StartNew(() =>
    UiDataProvider.RefreshForwardContractReport(fcrIdField.Value)
)
.ContinueWith(task => {
    if (task.Result.OperationSuccess)
    {
        // This updates the ObseravableCollection, should it be run on UI thread??
        RefreshReport(task.Result.OperationResult);
    }
});
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 5

WPF 在每个版本中都允许更多的跨线程操作。其他 MVVM 平台根本不允许它们。在 的情况下ObservableCollection,除非您正在使用 ,否则EnableCollectionSynchronization从后台线程更新是不正确的。

我同意 @avo 的观点,因为您应该将 ViewModel(您的逻辑UI)视为具有 UI 线程关联性(如文字UI)。所有数据绑定更新都应在 UI 上下文中完成。

正如@Cameron 指出的,这最容易通过async

var result = await Task.Run(
    () => UiDataProvider.RefreshForwardContractReport(fcrIdField.Value));
if (result.OperationSuccess)
{
  RefreshReport(result.OperationResult);
}
Run Code Online (Sandbox Code Playgroud)


Cam*_*and 4

延续在 UI 线程上运行的原因可能有多种。MVVM 框架可能会有所帮助,或者有其他东西让它在 UI 线程上运行,或者你只是运气好。

为了确保延续在 UI 线程上运行,您可以TaskScheduler像这样捕获之前的 UI。

var uiScheduler = TaskScheduler.FromCurrentSyncronizationContext();

Task.Factory.StartNew(() =>
    UiDataProvider.RefreshForwardContractReport(fcrIdField.Value),
    TaskCreationOptions.LongRunning
) // Ensures the task runs in a new thread
.ContinueWith(task => {
    if (task.Result.OperationSuccess)
    {
        RefreshReport(task.Result.OperationResult);
    }
}, uiScheduler); // Runs the continuation on the UI thread.
Run Code Online (Sandbox Code Playgroud)

这假设外部方法首先从 UI 运行。否则,您可以在顶层捕获 UI 调度程序并在应用程序中全局访问它。

如果你可以使用 async/await 那么代码就会变得更容易。

var result = await Task.Factory.StartNew(
    () => UiDataProvider.RefreshForwardContractReport(fcrIdField.Value),
    TaskCreationOptions.LongRunning
);

if (result.OperationSuccess)
{
    RefreshReport(result.OperationResult);
}
Run Code Online (Sandbox Code Playgroud)