簡體   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