gpt4 book ai didi

c# - 了解为什么 TPL 任务可以使用 OUT FromCurrentSynchronizationContext 更新 UI

转载 作者:行者123 更新时间:2023-11-30 17:01:39 25 4
gpt4 key购买 nike

我正在 VS2012、WPF 和 MVVM 中做一些 TPL。我有一个问题,我想我知道答案但想确定。考虑这个片段:

TaskCanceller = new CancellationTokenSource();
TaskLoader = Task<object>.Factory.StartNew(() =>
{
//Test the current query
DataRepository dr = new DataRepository(DataMappingSelected);
string test = dr.TestMappingConnection();
if (test.IsNotNullEmpty())
throw new DataConnectionException(test);

//Create the CSV File
DataQueryCsvFile CsvFile = new DataQueryCsvFile();
CsvFile.FileName = IO.Path.GetFileName(FilePath);
CsvFile.FilePath = IO.Path.GetDirectoryName(FilePath);

CsvFile.DataMapping = DataMappingSelected;
CsvFile.DataBrowserQuery = DataQueryHolder;

//Allow for updates to the UI
CsvFile.PageExportComplete += (s, e) =>
{
if (TaskCanceller.IsCancellationRequested)
(s as DataQueryCsvFile).IsSaveCancellationRequested = true;

StatusData = String.Format("{0} of {1} Complete", e.ProgressCount, e.TotalCount);
StatusProgress = (100 * e.ProgressCount / e.TotalCount);
};

CsvFile.SaveFile();

return CsvFile;
});

我有一个 DataQueryCsvFile 类。它的目的是根据一组传递的查询参数创建一个 CSV 文本文件,其结果可能非常大。因此导出对查询生成的表进行“分页”,这样就不会耗尽用户的内存。在其成员中有一个名为 PageExportComplete 的事件,每当将“页面”写入文件时调用该事件 - 比如说一次 1000 条记录。下面的代码使用此事件来更新 UI 上的进度指示器。

进度指示器(StatusData 和 StatusProgress)在 VM 中声明,并带有适当的 Notification,以便在更改时通知 View。例如:

public string StatusData
{
get { return _StatusData; }
set { NotifySetProperty(ref _StatusData, value, () => StatusData); }
}
private string _StatusData;

这是我的问题 - 事实上,这非常有效。但是为什么因为我没有声明要通过 ContinueWith 中的 UI 线程 (FromCurrentSynchronizationContext) 运行或更新的任务。

是因为MVVM模式吗?换句话说,因为正在更新的属性是 VM 的本地属性,并且因为它们有更新 View 的通知,并且因为通过绑定(bind)失去了耦合,它的工作原理是什么?或者我只是运气好,我应该通过声明 ContinueWith 来更新 UI 线程上的进度?

最佳答案

UI 相关的东西只能从 UI 线程更新,而绑定(bind)到 UI 的任何 CLR 属性都可以从后台线程更新,它们没有线程关联问题。

就像您在示例中发布的那样,您只是从后台线程更新 View 模型属性,这非常好但是如果您尝试直接更新进度条文本,它会掉得很惨 code> 因为 progressBar 是 UI 组件,只能从 UI 线程更新。


假设您将 TextBlock 绑定(bind)到 ViewModel 类中的 Name 属性:

<TextBlock x:Name="txt" Text="{Binding Name}"/>

如果您尝试直接更新文本,您将遇到著名的线程关联问题:

Task.Factory.StartNew(() => txt.Text = "From background");

但是如果您尝试更新 ViewModel Name 属性,它会正常工作,因为这里没有从后台线程访问 UI 内容:

ViewModelClass vm = DataContext as ViewModelClass;
Task.Factory.StartNew(() => vm.Name = "From background");

关于c# - 了解为什么 TPL 任务可以使用 OUT FromCurrentSynchronizationContext 更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20765085/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com