控制和取消多项任务
Control and cancel multiple tasks
我尝试编写简单的 WinForm 应用程序,但我对其行为有一些问题。
目的是在面板上绘制具有两种可选颜色(红色和黑色)的小矩形。有 4 个按钮 - 每种颜色配对 - 绘制红色、停止红色、绘制黑色、止黑.
当点击Draw按钮时,会生成新的DrawRectangles任务。
单击 停止 按钮时,将使用 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);
}
}
我想要做的是当我点击 停止 按钮时所有相同颜色的 运行 任务将被取消。
更新:
正如 Fabio 所建议的,我已经重写了我的点击方法以及受影响的方法。在那之后它会按需要工作。
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);
}
你的问题的根源在于,如果你点击 3 次 运行 任务按钮,你将运行 3 个任务与 3 个不同的取消令牌源。
由于 RunDrawingTask
中的这一行,您将覆盖刚刚传递给 RunDrawingTask
的取消令牌
cnTokenSource = new CancellationTokenSource();
如果您删除该行,您每次都会传递相同的令牌,您的所有任务都将能够对取消做出反应。
您的逻辑不符合您的要求。解决方案之一:
您需要创建两个 CancellationTokenSources:redCancelationTokenSource
和 blackCancelationokenSource
。并像这样重写 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);
并且当您想要停止绘图操作时,您必须在 CancellationTokenSources 之一上调用 'Cancel' 方法:redCancelationSource 或 blackCancelationSource。
我尝试编写简单的 WinForm 应用程序,但我对其行为有一些问题。 目的是在面板上绘制具有两种可选颜色(红色和黑色)的小矩形。有 4 个按钮 - 每种颜色配对 - 绘制红色、停止红色、绘制黑色、止黑.
当点击Draw按钮时,会生成新的DrawRectangles任务。 单击 停止 按钮时,将使用 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);
}
}
我想要做的是当我点击 停止 按钮时所有相同颜色的 运行 任务将被取消。
更新: 正如 Fabio 所建议的,我已经重写了我的点击方法以及受影响的方法。在那之后它会按需要工作。
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);
}
你的问题的根源在于,如果你点击 3 次 运行 任务按钮,你将运行 3 个任务与 3 个不同的取消令牌源。
由于 RunDrawingTask
中的这一行,您将覆盖刚刚传递给 RunDrawingTask
cnTokenSource = new CancellationTokenSource();
如果您删除该行,您每次都会传递相同的令牌,您的所有任务都将能够对取消做出反应。
您的逻辑不符合您的要求。解决方案之一:
您需要创建两个 CancellationTokenSources:redCancelationTokenSource
和 blackCancelationokenSource
。并像这样重写 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);
并且当您想要停止绘图操作时,您必须在 CancellationTokenSources 之一上调用 'Cancel' 方法:redCancelationSource 或 blackCancelationSource。