J'essaie d'écrire un code qui s'exécute lorsqu'une condition est remplie. Actuellement, je me sers de la boucle While ..., qui, je le sais, n’est pas très efficace. Je regarde aussi AutoResetEvent () mais je ne sais pas comment le mettre en œuvre de telle sorte qu'il continue de vérifier jusqu'à ce que la condition soit vraie.
Le code vit également dans une méthode asynchrone, alors peut-être qu’une sorte d’attente pourrait fonctionner?
private async void btnOk_Click(object sender, EventArgs e)
{
// Do some work
Task<string> task = Task.Run(() => GreatBigMethod());
string GreatBigMethod = await task;
// Wait until condition is false
while (!isExcelInteractive())
{
Console.WriteLine("Excel is busy");
}
// Do work
Console.WriteLine("YAY");
}
private bool isExcelInteractive()
{
try
{
Globals.ThisWorkbook.Application.Interactive = Globals.ThisWorkbook.Application.Interactive;
return true; // Excel is free
}
catch
{
return false; // Excel will throw an exception, meaning its busy
}
}
Je dois trouver un moyen de continuer à vérifier isExcelInteractive()
sans que le processeur soit bloqué dans une boucle.
Remarque : Il n'y a pas de gestionnaire d'événement dans Excel qui serait déclenché s'il n'est pas en mode édition.
Au moins, vous pouvez changer votre boucle d’un temps d’attente chargé à un sondage lent. Par exemple:
while (!isExcelInteractive())
{
Console.WriteLine("Excel is busy");
await Task.Delay(25);
}
Vous pouvez utiliser thread attente handler
private readonly System.Threading.EventWaitHandle waitHandle = new System.Threading.AutoResetEvent(false);
private void btnOk_Click(object sender, EventArgs e)
{
// Do some work
Task<string> task = Task.Run(() => GreatBigMethod());
string GreatBigMethod = await task;
// Wait until condition is false
waitHandle.WaitOne();
Console.WriteLine("Excel is busy");
waitHandle.Reset();
// Do work
Console.WriteLine("YAY");
}
alors un autre travail doit définir votre gestionnaire
void isExcelInteractive()
{
/// Do your check
waitHandle.Set()
}
Mise à jour: Si vous souhaitez utiliser cette solution, vous devez appeler isExcelInteractive () en continu, avec un intervalle spécifique:
var actions = new []{isExcelInteractive, () => Thread.Sleep(25)};
foreach (var action in actions)
{
action();
}
vous pouvez utiliser SpinUntil qui construit dans le .net-framework.
Après avoir fouillé beaucoup de choses, j'ai finalement trouvé une bonne solution qui n'accroche pas l'IC :) Adaptez-la à vos besoins!
public static Task WaitUntil<T>(T elem, Func<T, bool> predicate, int seconds = 10)
{
var tcs = new TaskCompletionSource<int>();
using(var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(seconds)))
{
cancellationTokenSource.Token.Register(() =>
{
tcs.SetException(
new TimeoutException($"Waiting predicate {predicate} for {elem.GetType()} timed out!"));
tcs.TrySetCanceled();
});
while(!cancellationTokenSource.IsCancellationRequested)
{
try
{
if (!predicate(elem))
{
continue;
}
}
catch(Exception e)
{
tcs.TrySetException(e);
}
tcs.SetResult(0);
break;
}
return tcs.Task;
}
}