我試着編寫簡單的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);
}
感謝您的回覆。如果我會採取你的解決方案,它會導致其他問題。如果在**停止後**點擊我想繼續繪圖並再次點擊**繪製紅色**我必須爲所有新繪製紅色任務續訂CancellationTokenSource(已取消)。在哪裏我會把這個代碼'cnTokenSource = new CancellationTokenSource();'? – Roni
在'RedBtn_Click'和'BlackBtn_Click'方法中,您可以觀察到屬性IsCancellationRequested(https://msdn.microsoft.com/en-us/library/system.threading.cancellationtokenslose.iscancellationrequested(v=vs.110) ).aspx)相應的'CTS'。如果設置爲true,則可以創建取消令牌源的新實例,設置相應的字段,並將其傳遞給'RunDrawingTask'方法。 –
Salalai謝謝。現在,在重寫'click'方法後,它效果很好!我會用重寫的方法更新我的問題。 – Roni