2012-07-07 27 views
4

因此,我在我的UI上有一個組合框,它在SelectionChanged上異步退出到Web服務以撤回某些信息以在UI上顯示(使用新的C#5 async/await關鍵字)。我想要做的是在發送新的請求之前取消當前的異步請求;例如,如果用戶使用鍵盤快速遍歷所有組合框項目,則即使第一個異步請求返回,SelectionChanged事件也可能會多次觸發(生成多個異步請求)。這會從組合框的SelectionChanged事件稱爲持續取消Async CancellationTokenSource的最佳實踐

所以我的異步函數如下所示:

public async Task<Connections> ConnectionsAsync() 
{ 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
} 

如果連接的是,熄滅並點擊了Web服務的屬性。所以,因爲CancellationTokenSource不能重複使用,一旦取消,我想這樣做的:

public async Task<Connections> ConnectionsAsync() 
{ 
    _cancellationTokenSource.Cancel(); 
    _cancellationTokenSource = new CancellationTokenSource(); 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
} 

的問題是,雖然有時候我會打電話取消()時,有沒有運行的異步命令(例如第一次這個函數被調用);所以如果我連接任何取消事件處理程序,他們將被調用,甚至在我做出異步請求之前。

無論如何檢查一個異步請求是否已經在運行?除了我做這樣的事情:

public async Task<Connections> ConnectionsAsync() 
{ 
    if (_runningAsyncCommand) 
     _cancellationTokenSource.Cancel(); 
    _cancellationTokenSource = new CancellationTokenSource(); 
    _runningAsyncCommand = true; 
    return await Task.Factory.StartNew(() => Connections, _cancellationTokenSource.Token); 
    _runningAsyncCommand = false; 
} 

我有全部使用相同CancellationTokenSource一些異步函數,所以我就必須實現所有這些功能這個「管道」。這是最好的方法嗎?或者,還有更好的方法?

另外,如果我公開地公開_cancellationTokenSource,以便其他類可以使用它註冊取消委託,那麼將這些委託「轉移」到新的CancellationTokenSource的最佳方法是什麼,因爲我每次都創建一個新的CancellationTokenSource?

在此先感謝!

+0

它解決了嗎?我現在有完全相同的問題。 – 2012-08-14 04:57:38

+0

不,它沒有解決,但現在回顧我的問題,我認爲正確的做法是將CancellationTokenSource的令牌作爲可選參數(即公共異步任務 ConnectionsAsync(CancellationToken token = null))。這樣用戶調用ConnectionsAsync()函數負責設置一個新的CancellationTokenSource並傳遞它的Token。 – deadlydog 2012-08-14 16:35:52

+0

所以在我的例子中,這會發生在我的ComboBox的SelectionChanged事件中;我將在現有的CancellationTokenSource上調用Cancel(),創建一個新的,並將其Token傳遞給ConnectionsAsync()函數。最後,儘管對於我的特定應用程序,我最終沒有使用取消。 – deadlydog 2012-08-14 16:45:28

回答

2

看起來像在天堂裏爲反應性擴展所做的配對。定義必須經過節流時間(比方說300毫秒)觀察從ComboBox的事件時創建的任務

代碼之前代碼段訂閱文本框更改事件,但你會得到的想法:

var input (from evt in Observable.FromEvent<EventArgs>(txt, "TextChanged") 
select ((TextBox)evt.Sender).Text) 
.Throttle(TimeSpan.FromSeconds(1)) 
.DistinctUntilChanged(); 

using (input.Subscribe(inp => Console.WriteLine("You wrote: " + inp))) 
{ 
    // Do stuff 
} 
+0

一個不錯的解決方案,但仍不完美。假設我對Web服務的請求需要3秒鐘才能返回。用戶可能仍然每2秒更換一次組合框選擇,在這種情況下,我仍然有同樣的問題。 我不想將油門設置得太高,例如2秒,否則每次改變選擇時都會有2秒的延遲,然後它才發送請求;因此從更改選擇到UI更新的時間總共需要5秒。 – deadlydog 2012-07-07 19:36:38

+0

您是否考慮實施(預先加載的)本地緩存機制?您是否真的需要從組合框更改選擇中檢索實時數據? – 2012-07-07 20:38:26

+0

我*可能*能夠爲我的特定情況緩存數據,因爲只有大約75個人可以更改我正在檢索的數據。原來的問題仍然有效,假設我的組合框列出了我的Twitter帳戶,當我選擇一個帳戶時,我想查看該帳戶的實時供稿。這是一個完美的例子,您總是需要實時數據。 – deadlydog 2012-07-08 04:57:10