取消异步任务

本文关键字:任务 异步 取消 | 更新日期: 2023-09-27 18:01:15

例如:当我点击第一个按钮,它开始的异步进程,然后我点击第二个按钮,它开始的第二个进程。但我只需要一个过程后,点击每个按钮工作。我如何取消其他进程?

namespace WpfApplication55
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        TestCombo TC = new TestCombo();
        public MainWindow()
        {
            DataContext = TC;
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TC.Begin(60);
        }
        private void Button_Click1(object sender, RoutedEventArgs e)
        {
            TC.Begin(120);
        }
    }
    public class TestCombo:INotifyPropertyChanged
    {
        private int someData;
        public int SomeData 
        {
            get { return someData; }
            set { someData = value; RaisePropertyChanged("SomeData"); }
        }
        public void StartCount(int input)
        {
            SomeData = input;
            while (input>0)
            {
                System.Threading.Thread.Sleep(1000);
                input -= 1;
                SomeData = input;
            }
        }
        public void Begin(int input)
        {   
            Action<int> Start = new Action<int>(StartCount);
            IAsyncResult result = Start.BeginInvoke(input, null, null);
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged (string info)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

取消异步任务

我不太确定你想要StartCount中的while条件如何工作,但只要你评估新的CancellationToken,你应该很好地取消。记住线程。睡眠在它睡觉的时候不会取消。所以你可能有最多15秒的延迟。

public void StartCount(int input, CancellationToken token)
{
    SomeData = input;
    while (input > 0 && !token.IsCancellationRequested)
    {
        System.Threading.Thread.Sleep(1000);
        input -= 1;
        SomeData = input;
    }
}
IAsyncResult process;
public void Begin(int input)
{
    if (process != null && !process.IsCompleted)
        ((CancellationTokenSource)process.AsyncState).Cancel();
    Action<int, CancellationToken> Start = new Action<int, CancellationToken>(StartCount);
    var cancelSource = new CancellationTokenSource();
    process = Start.BeginInvoke(input,cancelSource.Token, null, cancelSource);
}

我会使用微软的响应式框架。

这是你的类:

public class TestCombo : INotifyPropertyChanged
{
    private int someData;
    public int SomeData 
    {
        get { return someData; }
        set { someData = value; RaisePropertyChanged("SomeData"); }
    }
    private SingleAssignmentDisposable _subscription = new SingleAssignmentDisposable();
    public void Begin(int input)
    {
        _subscription.Disposable =
            Observable
                .Interval(TimeSpan.FromSeconds(1.0))
                .Select(x => input - (int)x)
                .Take(input)
                .ObserveOnDispatcher()
                .Subscribe(x => this.SomeData = x);
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged (string info)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}

这个解决方案的两个关键部分是第一个可观察查询订阅,它执行所有的计时,计算分配给SomeData的值,并将分配给UI线程的值封送。

第二个是SingleAssignmentDisposable。当你将一个新的IDisposable赋值给它的Disposable属性时,它将处理任何以前赋值的IDisposable

处置取消先前的订阅。

只需NuGet "Rx-WPF"来获取Rx的WPF位。

试试这样:

namespace WpfApplication55
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        TestCombo TC = new TestCombo();
        CancellationTokenSource cts;
        public MainWindow()
        {
            DataContext = TC;
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
            cts = new CancellationTokenSource();
            await TC.DoAsync(60, cts.Token);
        }
        private void Button_Click1(object sender, RoutedEventArgs e)
        {
            if (cts != null)
            {
                cts.Cancel();
            }
            cts = new CancellationTokenSource();
            await TC.DoAsync(120, cts.Token);
        }
    }
    public class TestCombo:INotifyPropertyChanged
    {
        private int someData;
        public int SomeData 
        {
            get { return someData; }
            set { someData = value; RaisePropertyChanged("SomeData"); }
        }
        public void StartCount(int input)
        {
            SomeData = input;
            while (input>0)
            {
                System.Threading.Thread.Sleep(1000);
                input -= 1;
                SomeData = input;
            }
        }
        public Task DoAsync(int input, CancellationToken cancellationToken)
        {   
            return Task.Run(StartCount, cancellationToken);
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged (string info)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

尝试使用类CancellationTokenSource;参见下面的代码-

CancellationTokenSource   ctstask = new CancellationTokenSource();
ctstask.Cancel();//This line should be called from 2nd button click.