简体   繁体   English

取消异步任务

[英]Cancel an async task

For example I have something like this. 例如,我有这样的事情。 When I am clicking on first button it start's async process and then I am clicking second button it start's second process. 当我单击第一个按钮时,它开始异步过程,然后单击第二个按钮,它开始第二个过程。 But I need only one process to work after clicking on each button. 但是单击每个按钮后,我只需要一个过程即可工作。 How can I cancel other process? 如何取消其他程序?

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

I'm not exactly sure how you want the while condition in StartCount to work but as long as you evaluating the new CancellationToken you should be good to cancel. 我不确定您希望StartCount中的while条件如何工作,但是只要您评估新的CancellationToken,就应该取消。 Remember the Thread.Sleep won't cancel while its sleeping. 请记住,Thread.Sleep在睡眠时不会取消。 So you may have up to a 1s delay. 因此,您最多可能会有1秒的延迟。

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

I would use Microsoft's Reactive Framework for this. 我将为此使用Microsoft的Reactive Framework。

Here's your class: 这是您的课程:

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

The two key parts to this solution is first the observable query subscription which does all of the timing, computes the value to assign to SomeData and marshals the assignment to the UI thread. 此解决方案的两个关键部分是首先执行所有计时的可观察查询订阅,计算要分配给SomeData的值并SomeData送给UI线程的分配。

The second is the SingleAssignmentDisposable . 第二个是SingleAssignmentDisposable When you assign a new IDisposable to its Disposable property it will dispose any previously assigned IDisposable . 当将新的IDisposable分配给其Disposable属性时,它将处置以前分配的任何IDisposable

The disposing cancels the previous subscription. 配置将取消先前的订阅。

Just NuGet "Rx-WPF" to get the WPF bits for Rx. 只需NuGet“ Rx-WPF”即可获得Rx的WPF位。

Try something like this: 尝试这样的事情:

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

Try using class CancellationTokenSource; 尝试使用类CancellationTokenSource; See code below- 请参阅下面的代码-

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM