2015-10-06 27 views
0

我試着編寫簡單的WinForm應用程序,並且我的行爲有問題。 目的是用兩種可選顏色(紅色&黑色)在面板上繪製小矩形。有4個按鈕 - 一對用於每個顏色 - 繪製紅色停止紅色繪製黑色停止黑色控制和取消多個任務

繪製按鈕被點擊時,的新任務繪製矩形被生成。 當停止按鈕被點擊時,任務將被取消,使用CancellationTokenSource。

問題是:當我創建了很多任務(即繪製紅色的3個任務)之後,我按下了停止按鈕,它取消了第一個任務,我無法取消其他任務(繪製紅色任務'),他們跑得無止境。

下面的代碼:

public partial class Form1 : Form 
{ 
    CancellationTokenSource cnDrawRedToken; 
    CancellationTokenSource cnDrawBlackToken; 
    public Form1() 
    { 
     InitializeComponent();   
    } 

    private void Form1_Load(object sender, EventArgs e{} 

    private void panel1_Paint(object sender, PaintEventArgs e){} 

    private void RedBtn_Click(object sender, EventArgs e) 
    { 
     RunDrawingTask(SetSpecificPen(Color.Red),out this.cnDrawRedToken);   
    } 

    private async Task DrawRectangles(int height, int width, Random random, Rectangle rectangle, Pen blackPen, CancellationToken cnToken) 
    { 
     while(true) 
     { 
      if (cnToken.IsCancellationRequested) 
       return; 
      rectangle.x = random.Next(0, width); 
      rectangle.y = random.Next(0, height); 
      this.panel1.CreateGraphics().DrawRectangle(blackPen, rectangle.x, rectangle.y, rectangle.width, rectangle.height); 
      //Thread.Sleep(200); 
      await Task.Delay(150); 
     } 
    } 

    private Pen SetSpecificPen(Color color) 
    { 
     Pen blackPen = new Pen(color, 2); 
     return blackPen; 
    } 

    private Rectangle InitRectangleWidthAndHeights() 
    { 
     Rectangle rectangle = new Rectangle(); 

     rectangle.width = 10; 
     rectangle.height = 10; 
     return rectangle; 
    } 

    private void StpRedBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawRedToken != null) 
     { 
      this.cnDrawRedToken.Cancel(); 
      this.cnDrawRedToken = null; 
     } 
     else 
     { 
      this.cnDrawRedToken = new CancellationTokenSource(); 
     } 
    } 

    private void BlackBtn_Click(object sender, EventArgs e) 
    { 
     RunDrawingTask(SetSpecificPen(Color.Black),out this.cnDrawBlackToken); 
    } 

    private void StpBlkBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawBlackToken != null) 
     { 
      this.cnDrawBlackToken.Cancel(); 
      this.cnDrawBlackToken = null; 
     } 
    } 

    private void RunDrawingTask(Pen specificPen, out CancellationTokenSource cnTokenSource) 
    { 
     int height = this.panel1.Height; 
     int width = this.panel1.Width; 
     Random random = new Random(); 
     Rectangle rectangle = InitRectangleWidthAndHeights(); 

     cnTokenSource = new CancellationTokenSource(); 
     CancellationTokenSource cts = cnTokenSource; 
     Task t = Task.Factory.StartNew(() => DrawRectangles(height, width, random, rectangle, specificPen, cts.Token), cts.Token); 
    } 
} 

,當我在停止按鈕顏色相同的所有正在運行的任務將被取消單擊我想要做的是。

更新: 由於法比奧建議,我已經重寫了我的點擊方法以及受影響的方法。在這之後,它會按需要工作。

public Form1() 
    { 
     InitializeComponent(); 
     cnDrawRedToken = new CancellationTokenSource() ; 
     cnDrawBlackToken = new CancellationTokenSource(); 
    } 
private void RedBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawRedToken.IsCancellationRequested) 
     { 
      this.cnDrawRedToken = null; 
      this.cnDrawRedToken = new CancellationTokenSource(); 
     }   
     RunDrawingTask(SetSpecificPen(Color.Red), this.cnDrawRedToken);   
    } 
private void StpRedBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawRedToken != null) 
     { 
      this.cnDrawRedToken.Cancel(); 
     }   
    } 

    private void BlackBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawBlackToken.IsCancellationRequested) 
     { 
      this.cnDrawBlackToken = null; 
      this.cnDrawBlackToken = new CancellationTokenSource(); 
     }    
     RunDrawingTask(SetSpecificPen(Color.Black), this.cnDrawBlackToken); 
    } 

    private void StpBlkBtn_Click(object sender, EventArgs e) 
    { 
     if (this.cnDrawBlackToken != null) 
     { 
      this.cnDrawBlackToken.Cancel();     
     } 
    } 

    private void RunDrawingTask(Pen specificPen, CancellationTokenSource cnTokenSource) 
    { 
     int height = this.panel1.Height; 
     int width = this.panel1.Width; 
     Random random = new Random(); 
     Rectangle rectangle = InitRectangleWidthAndHeights(); 

     Task t = Task.Factory.StartNew(() => DrawRectangles(height, width, random, rectangle, specificPen, cnTokenSource.Token), cnTokenSource.Token); 
    } 

回答

0

問題的根源在於,如果您單擊3次運行任務的按鈕,您將使用3種不同的取消標記源運行3個任務。

因爲這條線在RunDrawingTask,你會覆蓋您剛剛傳遞給RunDrawingTask

cnTokenSource = new CancellationTokenSource(); 

如果你刪除了這一行的取消標記,你每次都會經過同樣的道理,和你的任務將能夠對取消作出反應。

+0

感謝您的回覆。如果我會採取你的解決方案,它會導致其他問題。如果在**停止後**點擊我想繼續繪圖並再次點擊**繪製紅色**我必須爲所有新繪製紅色任務續訂CancellationTokenSource(已取消)。在哪裏我會把這個代碼'cnTokenSource = new CancellationTokenSource();'? – Roni

+0

在'RedBtn_Click'和'BlackBtn_Click'方法中,您可以觀察到屬性IsCancellationRequested(https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokenslose.iscancellationrequested(v=vs.110) ).aspx)相應的'CTS'。如果設置爲true,則可以創建取消令牌源的新實例,設置相應的字段,並將其傳遞給'RunDrawingTask'方法。 –

+1

Salalai謝謝。現在,在重寫'click'方法後,它效果很好!我會用重寫的方法更新我的問題。 – Roni

0

您的邏輯對您的要求無效。解決方案之一: 您需要創建兩個CancelationTokenSources:redCancelationTokenSourceblackCancelationokenSource。並改寫RunDrawingTask方法是這樣的:

private void RunDrawingTask(Pen pen, out CancellationTokenSource cnTokenSource) 
    { 
     int height = panel1.Height; 
     int width = panel1.Width; 
     Random random = new Random(); 
     Rectangle rectangle = InitRectangleWidthAndHeights(); 

     var cts = pen == blackPen ? blackTokenSource : redTokenSource; 
     Task.Factory.StartNew(() => DrawRectangles(height, width, random, rectangle, pen, cts.Token), cts.Token); 
    } 

    CancellationTokenSource blackTokenSource = new CancellationTokenSource(); 
    CancellationTokenSource redTokenSource = new CancellationTokenSource(); 

    Pen blackPen = new Pen(Color.Black); 
    Pen redPen = new Pen(Color.Red); 

,當你想停下來吸引你必須調用行動CancelationTokenSources的一個「取消」的方法:redCancelationSource或blackCancelationSource。

+0

也許我在你的例子中丟失了一些東西,但是取消指定的cnTokenSource在這裏對blackTokenSource和redTokenSource沒有任何影響,對吧? –

+0

不,你錯了。看看所有的應用程序,我們只有兩個cts。在這一行 'var cts = pen == blackPen?我們檢測到的blackTokenSource:redTokenSource',我們現在必須使用哪些cts(取決於筆)。所以如果你發送redPen - 將用'redCancelationToken'來創建一個新的任務。所以,當你取消'RedCancelationTokenSource'時,這個cts的所有任務都會中止。好?? –