2013-10-23 5 views
5

Ho il seguente compito che viene eseguito quando l'elemento di sezione di una casella di riepilogo cambia.Annullamento di tutte le attività quando viene creato uno nuovo

Sto tentando di annullare qualsiasi attività in esecuzione quando un utente modifica la selezione e avvia una nuova attività. Posso sembrare capire perché il codice non funziona.

Il codice

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; 
     } 

Così sto cercando di ottenere LoadSeriesAsync di annullare tutti gli altri eventi che sono in esecuzione e quindi eseguire solo LoadPosterAsync se LoadSeriesAsync è permesso di finire (l'utente non cambia selezione prima che venga caricato).

+0

Puoi essere più specifico su "non funziona"? – stuartd

+0

Spiacente, l'attività non viene annullata – justinf

+0

È necessario controllare manualmente 'token.IsCancellationRequested' in LoadSeriesAsync - vedere http://stackoverflow.com/a/3713113/43846 – stuartd

risposta

3

io sto cercando di ottenere LoadSeriesAsync per annullare tutti gli altri eventi che eseguono e poi solo corrono LoadPosterAsync se LoadSeriesAsync è permesso di finire

Quindi, basta controllare il token prima di chiamare LoadPosterAsync:

Nota a margine, si dovrebbe passare token in basso allo stack per qualsiasi operazione a esecuzione prolungata, ad esempio, TvdbHandler.GetSeries.

Inoltre, di solito è una cattiva idea fare catch (OperationCanceledException) { }; di solito, la semantica desiderata è di consentire la cancellazione di propagarsi.

+0

Ho provato il tuo suggerimento ma non sembra che i compiti vengano annullati. Ho messo un po 'di sonno prima di 'seriesloaded = m_tvdbHandler.GetSeries' in modo che, cambiando la selezione, rallentasse il compito quando cambiavo rapidamente selezione, vedo che c'è più di un compito e non è annullato. Questo è quello che sembrava [schermata dei compiti] (http://i.imgur.com/mRHpX42.jpg?1). – justinf

+0

Come ho notato nella mia risposta, è necessario modificare 'GetSeries' in modo che rispetti un token di cancellazione. –

+0

C'è un altro modo per farlo perché non posso cambiare GetSeries perché la sua funzionalità proviene da una dll personalizzata creata da qualcun altro, quindi non ho il controllo del codice. – justinf

-1

utilizzare Thread e alla selezione Controllare se Thread.IsAlive è uguale a true Thread.Abort() e quindi Thread.Start(); facile