【发布时间】:2019-07-25 14:28:28
【问题描述】:
.Net 4.5
我有一个任务列表
List<Task> lTasks
每个任务都有自己的
“CancellationTokenSource”和“cancellationToken”
Task.Id 和 Task.status
在 DataGridView 中列出。
DataGridView 中的每一行还有一个名为“StopTask”的按钮。
如果用户点击了“StopTask”按钮,该特定任务应该被取消
任务.Id
我该怎么做?
这是我每次调用时都会创建一个新任务的方法
private void CreateNewTask(int RowIndex)
{
CancellationTokenSource cts = new CancellationTokenSource(); //Init new CancellationTokenSource
var cancellationToken = cts.Token;
try
{
var t = Task.Factory.StartNew(() =>
{
Console.WriteLine("Start new task");
for (int i = 0; i < 100; i++)
{
dataGridView_TaskList.Rows[RowIndex].Cells["OutputValue1"].Value = i;
System.Threading.Thread.Sleep(1000);
}
cancellationToken.ThrowIfCancellationRequested();
}, cancellationToken);
lTasks.Add(t); //Add to Liast of tasks (List<Task>)
dataGridView_TaskList.Rows[RowIndex].Cells["TaskID"].Value = t.Id;
dataGridView_TaskList.Rows[RowIndex].Cells["TaskStatus"].Value = t.Status;
}
finally
{
cts.Dispose();
}
}
根据答案和 cmets,我做了以下操作,看起来效果很好。
我使用 DataGridView 作为我的“字典”并将每个任务的令牌保存在
dataGridView_TaskList.Rows[RowIndex].Cells["RowIndex"].Tag = cts;
我也用过
行索引
作为唯一 ID,因为两个任务可能具有相同的 TaskID。
新建任务如下图所示:
private async void CreateNewTask(int RowIndex)
{
CancellationTokenSource cts = new CancellationTokenSource(); //Init new CancellationTokenSource
var cancellationToken = cts.Token;
try
{
Task t = Task.Run(async () => //Task.Run automatically unwraps nested Task types!
{
try
{
Console.WriteLine("Start new task");
for (int i = 0; i < 100; i++)
{
// inside this loop the Token cancellation has no effect, it will keep running until this loop is finished then it will throw a cancellation exception
dataGridView_TaskList.Rows[RowIndex].Cells["OutputValue1"].Value = i;
await Task.Delay(300);
}
cancellationToken.ThrowIfCancellationRequested();
}
catch (OperationCanceledException ex)
{
ShowMsgBox.Show(ex.Message, "Cancelation", enumMessageIcon.Information, enumMessageButton.OK);
}
}, cancellationToken);
lTasks.Add(t); //Add to Liast of tasks (List<Task>)
dataGridView_TaskList.Rows[RowIndex].Cells["TaskID"].Value = t.Id; //The TaskId is not guaranteed to be unique
dataGridView_TaskList.Rows[RowIndex].Cells["TaskStatus"].Value = t.Status;
dataGridView_TaskList.Rows[RowIndex].Cells["RowIndex"].Value = RowIndex;
dataGridView_TaskList.Rows[RowIndex].Cells["RowIndex"].Tag = cts;
}
catch (Exception ex)
{
ShowMsgBox.Show(ex.Message, "Exception", enumMessageIcon.Error, enumMessageButton.OK);
}
}
可以取消任务,如下图所示
private void dataGridView_TaskList_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var senderGrid = (DataGridView)sender;
if (senderGrid.Columns[e.ColumnIndex] is DataGridViewButtonColumn &&
e.RowIndex >= 0)
{
if (senderGrid.Columns[e.ColumnIndex].Name is "StopTask")
{
//TODO - Button Clicked - Execute Code Here
int.TryParse(dataGridView_TaskList.Rows[e.RowIndex].Cells["RowIndex"].Value.ToString(), out int RowIndex);
CancellationTokenSource cts_ToBeCancelled = (CancellationTokenSource)dataGridView_TaskList.Rows[e.RowIndex].Cells["RowIndex"].Tag;
cts_ToBeCancelled.Cancel();
}
}
}
【问题讨论】:
-
把
cts放到 Rows 的标签... -
好主意,我会试试的
-
Id 不保证是唯一的,因此请勿将其用于此类目的。
-
Guid 也不能保证是唯一的,也许可以为您的警告提供上下文或范围?
-
@NineBerry 是对的,两个任务可能具有相同的 TaskID。因此,我使用 DataGridView 中的 RowIndex 作为唯一 ID
标签: c# cancellationtokensource cancellation-token