繁体   English   中英

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

[英]Understanding why TPL Task can update UI withOUT FromCurrentSynchronizationContext

我在VS2012中做一些TPL,用MVVM做WPF。 我有一个问题,我认为我知道答案但肯定想知道。 请考虑以下代码段:

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中声明并带有适当的通知,以便让View知道它们何时被更改。 例如:

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

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

是因为MVVM模式吗? 换句话说,因为要更新的属性对于VM是本地的,并且因为它们具有更新View的通知,并且由于通过绑定失去耦合,它的工作原理是什么? 或者我只是因为这种情况而幸运,我应该解决一下继续更新UI线程进度的问题?

UI related stuff can only be updated from UI thread而绑定到UI的任何CLR属性都可以从后台线程更新,它们没有线程亲和性问题。

就像你在样本中发布的一样, you are only updating View model properties from background thread which is perfectly fine但是如果你try updating Progress bar text directly, it will fall miserably因为progressBar是UI组件,只能从UI线程更新。


假设您在ViewModel类中将TextBlock绑定到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");

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM