2013-10-23 88 views
5

我有以下任務在列表框的部分項更改時運行。取消創建新的任務時的所有任務

我試圖取消任何正在運行的任務,當用戶更改他們的選擇並開始新的任務時正在運行。我似乎弄清楚爲什麼代碼無法正常工作。

CancellationTokenSource cts; 
// The event handeler for when the user makes a selection in the list box 
private async void lb1_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    clearfileds(); 

    if (cts != null) 
     { cts.Cancel(); } 

    cts = new CancellationTokenSource(); 

    var token = cts.Token; 
    string sid = lb1.SelectedItem.ToString(); 

    try 
    { 
     var series = await LoadSeriesAsync(token, Int32.Parse(sid)); 
     var poster = await LoadPosterAsync(series.PosterBanners[0]); 

     UpdateSeries(series); 
     if (File.Exists(poster)) 
     { 
      ImageSource imageSource = new BitmapImage(new Uri(poster)); 
      imgPoster.Source = imageSource; 
     } 
    } 
    catch (OperationCanceledException) 
    {MessageBox.Show("we cancell some thing");} 

    catch (FormatException) 
    {MessageBox.Show("Please enter a valid series id");} 

} 


private async Task<TvdbSeries> LoadSeriesAsync(CancellationToken ct, int _seriesId) 
    { TvdbSeries seriesloaded = null; 
     CancellationToken token = ct; 

     Task<TvdbSeries> SeriesLoadTask = Task.Run(() => 
     { 
      m_tvdbHandler = new TvdbHandler(CacheProvider, "49E28C3EB13EB1CF"); 
      m_tvdbHandler.InitCache(); 
      token.ThrowIfCancellationRequested(); 

      try 
      { seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true); 
       //Just for the test 
       System.Threading.Thread.Sleep(9000); 
      } 

      catch (OperationCanceledException) 
      { } 

      catch (TvdbInvalidApiKeyException ex) 
      { MessageBox.Show(ex.Message);} 
      catch (TvdbNotAvailableException ex) 
      { MessageBox.Show(ex.Message);} 

      return seriesloaded; 
     }); 

     try 
     { seriesloaded = await SeriesLoadTask; } 

     catch (OperationCanceledException) 
       {} 
     return seriesloaded; 
    } 


private async Task<string> LoadPosterAsync(object _param) 
     { 
      string posterpath ; 
      Task<string> PosterLoad = Task.Run(() => 
      { 

       TvdbPosterBanner banner = (TvdbPosterBanner)_param; 
       banner.LoadBanner(); 
       posterpath = CacheFolder + @"\" + banner.SeriesId + @"\img_posters_" + (banner.BannerPath).Replace(@"posters/", ""); 
       return posterpath; 
      }); 


      try 
      { posterpath = await PosterLoad; } 

      catch (OperationCanceledException) 
       { 
        posterpath = ""; 
       } 
      return posterpath; 
     } 

所以我試圖讓LoadSeriesAsync取消所有正在運行的其他事件,然後只運行LoadPosterAsync如果LoadSeriesAsync被允許完成的代碼(用戶在加載之前不會改變選擇)。

+0

你能更具體地說「不工作」嗎? – stuartd

+0

對不起,任務不會被取消 – justinf

+0

您需要在LoadSeriesAsync中手動檢查'token.IsCancellationRequested' - 請參閱http://stackoverflow.com/a/3713113/43846 – stuartd

回答

3

我試圖讓LoadSeriesAsync取消正在運行,然後才LoadSeriesAsync被允許完成

所以,只要檢查令牌調用LoadPosterAsync之前運行LoadPosterAsync所有其他事件:

var series = await LoadSeriesAsync(token, Int32.Parse(sid)); 
token.ThrowIfCancellationRequested(); 
var poster = await LoadPosterAsync(series.PosterBanners[0]); 

在附註中,您應該將token向下傳遞給任何長時間運行的操作,例如TvdbHandler.GetSeries

另外,做catch (OperationCanceledException) { }通常是個壞主意;通常,所需的語義是允許取消傳播出去。

+0

我試過你的建議,但似乎沒有任務被取消。我在'serialloaded = m_tvdbHandler.GetSeries'之前進行了一次睡眠,這樣當我改變選擇時,它會在選擇很快改變時減慢任務速度,我看到有多個任務沒有取消。這就是[任務畫面](http://i.imgur.com/mRHpX42.jpg?1)。 – justinf

+0

正如我在我的回答中指出的那樣,您需要修改'GetSeries',以使其支持取消令牌。 –

+0

是否有另一種方法來做到這一點,因爲我不能改變GetSeries,因爲它的功能來自其他人制作的自定義dll,所以我無法控制代碼。 – justinf

-1

use Thread and at selection檢查Thread.IsAlive是否等於true Thread.Abort()然後Thread.Start();容易