繁体   English   中英

取消异步任务

[英]Cancel an async task

例如,我有这样的事情。 当我单击第一个按钮时,它开始异步过程,然后单击第二个按钮,它开始第二个过程。 但是单击每个按钮后,我只需要一个过程即可工作。 如何取消其他程序?

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,就应该取消。 请记住,Thread.Sleep在睡眠时不会取消。 因此,您最多可能会有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);
}

我将为此使用Microsoft的Reactive Framework。

这是您的课程:

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的值并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.

暂无
暂无

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

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