web-dev-qa-db-fra.com

C # Attendre que la condition soit vraie

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. 

20
Keylee

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);
    }
24
Ben Voigt

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();
}
8
Peyman

vous pouvez utiliser SpinUntil qui construit dans le .net-framework.

2
anion

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;
    }
}
0
Oğuzhan Soykan