简体   繁体   中英

C# pause foreach loop until button pressed

Using C#, I have list of methods (Actions). I then have a method to invoke action using a foreach loop. A button click calls the method which in turn invokes every action in the list in one go. What I am after is for the click to only execute one action per click. Thanks in advance.

private static List<Action> listOfMethods= new List<Action>();

listOfMethods.Add(() => method1());
listOfMethods.Add(() => method2());
listOfMethods.Add(() => method3());
//====================================================================
private void invokeActions()
{
   foreach (Action step in listOfMethods)
   {
       step.Invoke();
       //I want a break here, only to continue the next time the button is clicked
   }
}
//====================================================================
private void buttonTest_Click(object sender, EventArgs e)
    {
        invokeActions();
    }

You can add a step counter :

private static List<Action> listOfMethods= new List<Action>();
private static int stepCounter = 0;

listOfMethods.Add(() => method1());
listOfMethods.Add(() => method2());
listOfMethods.Add(() => method3());
//====================================================================
private void invokeActions()
{
       listOfMethods[stepCounter]();

       stepCounter += 1;
       if (stepCounter >= listOfMethods.Count) stepCounter = 0;
}
//====================================================================
private void buttonTest_Click(object sender, EventArgs e)
    {
        invokeActions();
    }

You need to persist some state in between button clicks, so that you know where you left off from the last time. I suggest using a simple counter:

private int _nextActionIndex = 0;

private void buttonTest_Click(object sender, EventArgs e)
{
    listOfMethods[_nextActionIndex]();
    if (++_nextActionIndex == listOfMethods.Count)
        _nextActionIndex = 0;    // When we get to the end, loop around
}

This executes the first action, then the next, etc. each time the button is pressed.

First write a method to generate a Task when a particular Button is next pressed:

public static Task WhenClicked(this Button button)
{
    var tcs = new TaskCompletionSource<bool>();
    EventHandler handler = null;
    handler = (s, e) =>
    {
        tcs.TrySetResult(true);
        button.Click -= handler;
    };
    button.Click += handler;
    return tcs.Task;
}

Then just await it in your method when you want it to continue after the next button press:

private async Task invokeActions()
{
    foreach (Action step in listOfMethods)
    {
        step.Invoke();
        await test.WhenClicked();
    }
}

If you only need to execute the methods once, I would suggest adding them to a Queue<T> so state does not need to be maintained.

private static Queue<Action> listOfMethods = new Queue<Action>();
listOfMethods.Enqueue(method1);
listOfMethods.Enqueue(method2);
listOfMethods.Enqueue(method3);   

private void buttonTest_Click(object sender, EventArgs e) {
    if (listOfMethods.Count > 0) {
        listOfMethods.Dequeue().Invoke();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM