在C#中取消任务

时间:2016-11-28 08:05:23

标签: c#

我有一个带有两个按钮的表单(开始停止)。

当我按开始按钮时,任务会被初始化,并且会调用一个一直运行的功能,直到按下停止按钮。

但是当我按停止按钮时,表单会冻结。为什么? 我已经从StackOverflow复制了片段,但它仍然冻结了Form。 那么请告诉我如何正确取消任务?

public partial class Form1 : Form
{
    private readonly CancellationTokenSource _cts = new CancellationTokenSource();
    private Task _task;

    public Form1()
    {
        InitializeComponent();
    }

    //Funtion that runs when Task is initialized.
    private void EventLoop(CancellationToken token)
    { 
        //Code here..
        while (!token.IsCancellationRequested)
        {
            //Code here..
        }
        if (token.IsCancellationRequested)
        {
            MessageBox.Show("Operation Complete..!!");
        }

    }

    //Function for Start Button.
    private void Start_Click(object sender, EventArgs e)
    {
        _task = Task.Factory.StartNew(() => EventLoop(_cts.Token), _cts.Token);
    }

    //Function for Stop button.
    private void Stop_Click(object sender, EventArgs e)
    {
         _cts.Cancel();
    }
}

来自MSDN的类似示例:

var compute = Task.Factory.StartNew(() =>
{
    return SumRootN(j);
}, tokenSource.Token);`

表格按停止按钮后。 token.IsCancellationRequested true

Freeze Form

完整EventLoop()功能。

private void EventLoop(CancellationToken token)
    {
        SerialPort sp = new SerialPort();
        string text, batch, part, courseName;
        text = batch = part = courseName = "";
        int courseId = 0;

        this.Invoke((MethodInvoker)delegate()
        {
            text = portCB.SelectedItem.ToString();
            batch = comboBox2.SelectedItem.ToString();
            part = comboBox3.SelectedItem.ToString();
            courseName = comboBox1.SelectedItem.ToString();
            progressBar1.Value = 20;
            using (Model1 db = new Model1())
            {
                courseId = db.Courses.Where(c => c.Course_name.ToUpper() == courseName.ToUpper()).Select(c => c.Course_Id).Single();
            }
        });

        sp.PortName = text;
        sp.BaudRate = 9600;
        sp.Open();

        while (!token.IsCancellationRequested)
        {
            text = sp.ReadLine();

            if (text.Contains("Found ID #"))
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    textBox2.Clear();
                    textBox2.Text = "Getting Registation ID.\n";
                    progressBar1.Value = 60;
                });

                string splitText = text.Split('#')[1];
                int end = splitText.IndexOf(' ');
                int id = int.Parse(splitText.Substring(0, end));

                using (Model1 db = new Model1())
                {
                    var result = db.Students.Where(s => s.Reg_Id == id && s.Batch == batch && s.Class == part).Select(s => s).SingleOrDefault();
                    if (result != null)
                    {
                        Attendance a = new Attendance();
                        a.Course_Id = courseId;
                        a.Student_Id = id;
                        a.Status = "P";
                        a.Date = DateTime.Today.Date;
                        a.Batch = batch;
                        a.Part = part;

                        db.Attendances.Add(a);
                        string message = "";

                        if (db.SaveChanges() != 0)
                        {
                            message = "Attendance Uploaded..!!\n";
                        }
                        else
                        {
                            message = "Attendance Not Uploaded ..!!\n";
                        }

                        this.Invoke((MethodInvoker)delegate()
                        {
                            progressBar1.Value = 100;
                            textBox2.AppendText(message);
                        });
                    }
                    else
                    {
                        this.BeginInvoke((MethodInvoker)delegate()
                        {
                            textBox2.AppendText("Student Does not belong to Specified Batch Or Part..\n");
                        });
                    }
                }
            }
            else
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    textBox2.AppendText("No Match Found..!! \n");
                });
            }
            this.Invoke((MethodInvoker)delegate()
             {
                 textBox1.AppendText(text + "\n");
             });
        }
        sp.Close();

        // This exception will be handled by the Task
        // and will not cause the program to crash
        if (token.IsCancellationRequested)
        {
            //MessageBox.Show("Operation Comptele..!!");
        }
    }

2 个答案:

答案 0 :(得分:3)

您在取消过程中致电MessageBox.Show("Operation Complete..!!");。这是非常不推荐的,不是说你从UI线程以外调用UI操作。

评论MessageBox.Show("Operation Complete..!!");

*编辑*

问题作者对他原来的问题发表评论,发现了错误,哪一行已从帖子中删除。以下是我的结论:

始终尝试隔离问题,并以最纯粹的形式重现。在此过程中,您可能会自行诊断并找到问题: - )。

因此,如果有问题的代码很长,那么绝对不是删除行然后发布的方式。方法是删除行并查看问题是否存在,换句话说:以最纯粹的可重复形式隔离问题

答案 1 :(得分:-1)

请在您的任务中使用异步调用

  private async void Start_Click(object sender, EventArgs e)
  {
        _task = Task.Factory.StartNew(() => EventLoop(_cts.Token), _cts.Token);
        await task;       
  }