2016-11-28 92 views
2

我有一個帶有兩個按鈕的窗體(開始,停止)。在C中取消任務#

當我按下開始按鈕任務被初始化,一個函數被調用的是繼續工作,直到停止按鈕被按下。

但是當我按停止按鈕表單凍結。爲什麼? 我已經從StackOverflow複製片段,但它仍凍結窗體。 那麼告訴我如何正確取消任務?從MSDN

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

類似的實施例:按鈕被按下停止

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

窗體後token.IsCancellationRequestedtrue

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..!!"); 
     } 
    } 
+0

這顯然是非常,非常邋遢使用異步調用,但我沒有看到任何會導致僵局的事情。當然你沒有在'CancellationToken'上註冊取消回調或者在任何地方調用'_task.Wait' /'_task.Result'? –

+0

沒有我沒有做任何事情,除了啓用和禁用CheckBoxes在**開始**和**停止**按鈕Codding ..我可以告訴你,但然後大家會downvote我的問題.. –

+2

截圖中的窗體很清楚禁用,但我沒有看到窗體的'Enabled'屬性被設置在代碼中的任何地方,所以我傾向於認爲問題發生在未發佈的代碼部分。 –

回答

3

您在取消進度中致電MessageBox.Show("Operation Complete..!!");。這是非常不推薦的,不是說你從UI線程以外調用UI操作。

評論的MessageBox.Show("Operation Complete..!!");線路輸出

*編輯*

問作者對他原來的問題評論,發現錯誤,從後取出哪條線路。下面是我的結論:

始終嘗試找出問題,並在其最純粹的形式重現。在這個過程中,你可能會診斷並發現問題本身:-)。

所以,如果問題的代碼是很長的帖子,這絕對不是隻刪除行然後發佈它的方式。該方法是刪除線,看看問題是否存在,與其他詞:在其最純粹的可再現的形式隔離問題

+0

我已評論過,但仍然凍結。 –

+0

請問您可以在while循環內發佈代碼嗎? –

+0

其非常冗長...我不想得到負面的投票,已經被禁止的邊緣。但我會承擔風險。 –

-1

請在您的任務

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