簡體   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