2013-10-23 23 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

私はあなたがLoadPosterAsyncを呼び出す前に、ちょうどトークンをチェックし、LoadSeriesAsyncが実行されている他のすべてのイベントをキャンセルし、LoadSeriesAsyncがそう

を完了するために許可されている場合のみLoadPosterAsyncを実行するために取得しようとしています:

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

tokenを長時間実行しているオペレーション(例:TvdbHandler.GetSeries)に渡す必要があります。

また、通常はcatch (OperationCanceledException) { }を実行することは悪い考えです。通常、望ましいセマンティクスは、取り消しを伝播させることです。

+0

私はあなたの提案を試みましたが、タスクがキャンセルされているようではありません。私は 'seriesloaded = m_tvdbHandler.GetSeries'の前に眠るようにしました。選択を変更すると、選択をすばやく変更するときにタスクが遅くなるので、複数のタスクがあり、取り消されません。これは、[タスクの画面](http://i.imgur.com/mRHpX42.jpg?1)のように見えます。 – justinf

+0

私の答えで述べたように、キャンセルトークンを尊重するように 'GetSeries'を修正する必要があります。 –

+0

私はGetSeriesを変更できないため、他の人が作成したカスタムDLLからその機能が提供されるため、コードを制御することができないため、別の方法がありますか? – justinf

-1

を使用スレッドと選択時Thread.IsAliveがtrueの場合はThread.Abort()を実行し、次にThread.Start()を実行します。簡単に