Использование CancellationTokenSource для выполнения только одной задачи - PullRequest
0 голосов
/ 04 октября 2019

Во-первых, мое приложение находится в WPF. Во-вторых, у меня есть метод задачи, чтобы обновить некоторые представления, которые мне нужно выполнить только один раз. Итак, если метод вызывается во второй раз до завершения первого, он отменяет первый метод задачи.

Чтобы достичь этого, я нашел решение, которое «работает» в целом, но иногда у меня естьисключение "hwnd не может быть IntPtr.Zero или null."И я не понимаю, почему мое первое решение не работает.

«Рабочее» решение:

private Tuple<Task, CancellationTokenSource> _manageErrorTask;
private void RefreshMyList()
{
    if (_manageErrorTask != null && !_manageErrorTask.Item1.IsCompleted)
    {
        _manageErrorTask.Item2.Cancel();
        _manageErrorTask.Item2.Dispose();
        _manageErrorTask.Item1.Dispose();
        _manageErrorTask = null;
    }

    var token = new CancellationTokenSource();
    CancellationToken ct = token.Token;
    ct.Register(() => Console.WriteLine("Cancel Token !! "));

    Task task = Task.Run(() =>
    {
        // Were we already canceled?
        if (ct.IsCancellationRequested) return;

        try
        {
            foreach (var userControl in MyList)
            {
                RT(() =>
                {
                    Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
                    {
                        var vm = userControl.DataContext as ViewModelBase;
                        vm?.Refresh("yololo");
                    }));

                },
                ct);

            }
        }
        catch(Exception e)
        {
            //Do nothing
        }

    }, ct);

    _manageErrorTask = Tuple.Create(task, token);
}

public static void RT(Action action, CancellationToken token)
{
    if (action == null)
        return;
    Task.Run(async () => {
        if (!token.IsCancellationRequested)
        {
            action();

        }
    }, token);
}

Мое решение, которое не работает:

private Tuple<Task, CancellationTokenSource> _manageErrorTask;
private void RefreshMyList()
{
    if (_manageErrorTask != null && !_manageErrorTask.Item1.IsCompleted)
    {
        _manageErrorTask.Item2.Cancel();
        _manageErrorTask.Item2.Dispose();
        _manageErrorTask.Item1.Dispose();
        _manageErrorTask = null;
    }

    var token = new CancellationTokenSource();
    CancellationToken ct = token.Token;
    ct.Register(() => Console.WriteLine("Cancel Token !! "));

    Task task = Task.Run(() =>
    {
        // Were we already canceled?
        if (ct.IsCancellationRequested) return;

        try
        {
            foreach (var userControl in MyList)
            {
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
                {
                    var vm = userControl.DataContext as ViewModelBase;
                    vm?.Refresh("yololo");

                    ct.ThrowIfCancellationRequested();

                }));
            }
        }
        catch(Exception e)
        {
            //Do nothing
        }
    }, 
    ct);

    _manageErrorTask = Tuple.Create(task, token);
}


...