2014-11-24 23 views
4

在我的windows phone 8.1應用程序中,我有一個單例服務DataService,它應該偶爾下載一些數據。同時在UI上,我應該顯示收到的數據量。 DataService.StartGettingData()被調用時,用戶登錄到應用程序:該應用程序稱爲一個接口,該接口被編組爲另一個線程。 (來自HRESULT的異常:0x8001010E(RPC_E_WRONG_THREAD))

void StartGettingData() 
{ 
    if (getDataTaskCancellationTokenSource != null) 
     getDataTaskCancellationTokenSource.Cancel(); 

    getDataTaskCancellationTokenSource = new CancellationTokenSource(); 
    var token = getDataTaskCancellationTokenSource.Token; 

    Task.Factory.StartNew(async() => await ExecuteCycleAsync(token), token); 
} 

async Task ExecuteCycleAsync(CancellationToken cancellationToken) 
{ 
    while (true) 
    { 
     cancellationToken.ThrowIfCancellationRequested(); 
     await LoadDataAsync(cancellationToken); 
     cancellationToken.ThrowIfCancellationRequested(); 
     await Task.Delay(timeTillNextDownload, cancellationToken); 
    } 
} 

當用戶註銷與

if (getDataTaskCancellationTokenSource != null) 
    getDataTaskCancellationTokenSource.Cancel(); 

幫助包含的下載貌似結果的屬性該任務將被取消這個:

List<DataType> Data = new List<DataType>(); 
public IEnumerable<DataType> Data 
{ 
    get { return Data; } 
    set 
    { 
     Data = value.ToList(); 
     OnDataUpdated(); 
    } 
} 

void OnDataUpdated() 
{ 
    var handler = DataUpdated; 
    if (handler != null) 
     handler(this, EventArgs.Empty); 
} 

這部分似乎工作,直到我必須顯示屏幕上的數據量。 我的MainViewModel獲取注入Ninject的DataService的實例。

readonly IDataService DataService; 

public MainViewModel(IDataService dataService) 
{ 
    DataService = dataService; 
    DataService.DataUpdated += DataService_DataUpdated; 
    UpdateDataCount(); 
} 

void DataService_DataUpdated(object sender, EventArgs e) 
{ 
    UpdateDataCount(); 
} 

void UpdateDataCount() 
{ 
    DataCount = DataService.Data.Count(); 
} 

在XAML我已經得到的TextBlock綁定到MainViewModel

int DataCount; 
public int DataCount 
{ 
    get { return DataCount; } 
    set 
    { 
     DataCount = value; 
     OnPropertyChanged(); 
    } 
} 

protected void OnPropertyChanged([CallerMemberName] string propertyName = "") 
{ 
    PropertyChangedEventHandler handler = PropertyChanged; 
    if (handler != null) 
    { 
     handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

的DATACOUNT財產,這裏是哪裏的問題出現:OnPropertyChanged失敗, 「的應用程序調用這是整理爲不同的接口線程(來自HRESULT的異常:0x8001010E(RPC_E_WRONG_THREAD))「,它被DataService.LoadDataAsync()捕獲。 我知道運行時正試圖告訴我,我正在從非UI線程訪問UI元素。但我呢?我認爲OnPropertyChanged是將UI與其他後臺任務斷開的神奇之處。 當然,這個問題是可以解決的實施OnPropertyChanged這樣:

public CoreDispatcher Dispatcher { get; set; } 

protected async void OnPropertyChanged([CallerMemberName] string propertyName = "") 
{ 
    PropertyChangedEventHandler handler = PropertyChanged; 
    if (handler != null) 
    { 
     await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,() => 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     }); 
    } 
} 

但如果真的被這種方式實現?或者我在DataService.ExecuteCycleAsync()中丟失了什麼?

+1

您在哪裏創建視圖模型的新實例,以及它如何與您的xaml連接? – 2014-11-24 16:48:35

+1

您是否在單獨的線程中運行取決於從哪裏調用OnDataUpdated。我懷疑它是在LoadDataAsync方法中,如果是的話,那麼是的,它是在一個單獨的線程中。沒有什麼魔法可以使用戶界面線程可以證明,所以你的方法是正確的。 – Kell 2014-11-24 16:52:56

+0

@Kell,OnDataUpdated在IEnumerable內部調用數據,所以我猜想它正在後臺線程上運行。 – foxanna 2014-11-24 20:38:33

回答

7

不是要挖得更深,我相信你的問題是這樣的:

Task.Factory.StartNew(async() => await ExecuteCycleAsync(token), token); 

改變它只是這一點,看看它是否按預期工作:

ExecuteCycleAsync(token); 

,否則裏面的代碼ExecuteCycleAsync在沒有同步上下文的線程上啓動執行,這可能會導致所有不同類型的問題,具體取決於LoadDataAsync中的內容。

請注意,像這樣撥打ExecuteCycleAsync(token)仍然是一個即忘即用的通話,可能不會有任何例外(更多here)。您可能想要存儲它返回的Task對象,以便稍後觀察它。

相關問題