Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cancelling all tasks when a new one is created

I have the following task that is run when the section item of a list box changes.

I am trying to cancel any task that are running when a user changes their selection and start a new task . I can seem to figure out why the code is not working.

The code

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

So I am trying to get LoadSeriesAsync to cancel all other events that are running and then only run LoadPosterAsync if LoadSeriesAsync is allowed to finish (user does not change selection before it is loaded).

like image 287
justinf Avatar asked Nov 01 '22 12:11

justinf


1 Answers

I am trying to get LoadSeriesAsync to cancel all other events that are running and then only run LoadPosterAsync if LoadSeriesAsync is allowed to finish

So, just check the token before you call LoadPosterAsync:

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

On a side note, you should be passing token down the stack to any long-running operations, e.g., TvdbHandler.GetSeries.

Also, it's usually a bad idea to do catch (OperationCanceledException) { }; usually, the desired semantics are to allow the cancellation to propagate out.

like image 110
Stephen Cleary Avatar answered Nov 13 '22 02:11

Stephen Cleary