C# 如果第一个代码正在执行,如何等待?
我遇到过这样一种情况:当用户单击tabitem时,用户创建了一个类的实例。这个类包含一个绘制图形的函数,它非常耗时,所以是异步编写的 现在的问题是,假设用户第一次单击tab,类实例化,长流程长时间工作,同时之前的异步任务没有找到,用户再次单击同一个tabitem 在这种情况下,我必须等到上一个异步任务未完成,然后在第二次单击tabitem时,必须在第一个异步任务完成后创建实例(应该等到第一个异步进程未完成) 代码如下:C# 如果第一个代码正在执行,如何等待?,c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,我遇到过这样一种情况:当用户单击tabitem时,用户创建了一个类的实例。这个类包含一个绘制图形的函数,它非常耗时,所以是异步编写的 现在的问题是,假设用户第一次单击tab,类实例化,长流程长时间工作,同时之前的异步任务没有找到,用户再次单击同一个tabitem 在这种情况下,我必须等到上一个异步任务未完成,然后在第二次单击tabitem时,必须在第一个异步任务完成后创建实例(应该等到第一个异步进程未完成) 代码如下: if (selectedTabIndex == 2) //What is t
if (selectedTabIndex == 2) //What is the user selected second time whil the previous task is still not finshed ?
{
DrawGraph obj= new DrawGraph(selectedItem.Name);
}
在DrawGraph类构造函数中的某个地方,我做过:
public DrawGraph(string Name)
{
timeConsumingProcess(Name);
}
public async void timeConsumingProcess(string Name)
{
await startTaimeConsumingProcess();
}
我想要的是,当用户第二次单击此选项卡项编号=2时,它必须等待finsh执行上一个异步任务,然后它必须再次实例化DrawGraph类
重新启动异步
如何实现它?一个简单的改变就能实现这一点
public async Task DrawGraph(string Name)
{
await timeConsumingProcess(Name);
}
public async Task timeConsumingProcess(string Name)
{
await startTaimeConsumingProcess();
}
我让
DrawGraph()
返回一个任务
,以防您需要等待它。如果这是一个非常耗时的过程,您可以选择在不同的线程中执行
public DrawGraph(string Name)
{
var task = new Task(() => timeConsumingProcess(Name));
task.Start();
}
这样你的主线程就不会被阻塞。如果要在长时间运行的任务完成后运行某些代码,请使用ContinueWith方法
public DrawGraph(string Name)
{
_canPressTab = false;
var task = new Task(() => timeConsumingProcess(Name));
task.Start();
task.ContinueWith(t => {
_canPressTab = true;
...
});
}
更新如下
如图所示,单击选项卡时可以调用Draw方法。这将检查任务是否已在运行。如果没有,则启动任务。如果任务正在运行,它将等待任务完成,然后启动新任务
public Task task = new Task(DoSomething);
private static void DoSomething()
{
Thread.Sleep(10000);
}
private void Draw()
{
//if tab is clicked run the Draw method
if (task.Status.Equals(TaskStatus.Running))
{
task.Wait();
task = new Task(DoSomething);
task.Start();
}
else if (task.Status.Equals(TaskStatus.RanToCompletion))
{
task = new Task(DoSomething);
task.Start();
}
else
{
task.Start();
}
}
您可以将表示长时间运行的操作的任务存储在表单中的实例变量中,并使用它检查任务是否仍在运行
private Task drawGraphTask = null;
private void button1_Click(object sender, EventArgs e)
{
DrawGraph();
}
private async void DrawGraph()
{
// Only perform task when this is the first time
// or the previous task is already completed
if (drawGraphTask == null || drawGraphTask.IsCompleted)
{
drawGraphTask = startTimeConsumingProcess();
await drawGraphTask;
}
else
{
MessageBox.Show("Task already active");
}
}
private Task startTimeConsumingProcess()
{
// Your Code here
return Task.Delay(5000);
}
从构造函数内部启动异步活动是不好的。将异步逻辑移到DrawGraph类之外,并使该类在表单级别的实例化成为异步的
在这种情况下,我必须等到上一个异步任务尚未完成,然后在第二次单击tabitem时,必须在第一个异步任务完成后创建实例
然后让代码(a)等待最后一个任务:
private Task drawGraph = null;
...
if (selectedTabIndex == 2)
{
if (drawGraph != null)
await drawGraph;
DrawGraph obj = new DrawGraph(selectedItem.Name);
drawGraph = obj.timeConsumingProcess();
}
...
private readonly string name;
public DrawGraph(string Name)
{
name = Name;
}
public async Task timeConsumingProcess()
{
await startTaimeConsumingProcess();
}
请注意,这要求您使用
async Task
而不是async void
,这很好,因为您应该禁用该选项卡。为什么不禁用该选项卡?@HristoYankov是的,我有这个想法,但我的上级不接受。使用wait不会阻止处理用户操作,因此问题仍然存在。@NineBerry您说得对。但这不是用户所要求的。用户要求任务等待,即使按钮已按下。因此,对DrawGraph()
的下一个调用将等待上一个调用完成。我要做的是在previosu任务处理时,在if(selectedTabIndex==2)条件下等待。如果正在处理,则让它查找,然后处理下一个实例。如何执行?条件drawGraphTask==null甚至会在第二次单击时执行,因为第二次单击后调试时的参数是“Id=744,Status=RanToCompletion,Method=“{null}”,但它仍然执行该条件否,该条件检查整个任务是否为null,任务的Method属性具有什么值并不重要。