Search code examples
c#wpfinfinite-loopcoroutine

An infinite loop in WPF C# (awaited async method calls in an endless loop)


I'm trying to write a "life" game in WPF C# ( https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life ). I have a problem with creating a loop to write the logic of the game itself. I have a button in the MainWindow class (below): MainWindow.xaml.cs

private void Start_Click(object sender, RoutedEventArgs e)         
        {                                                                  
            Restart.Visibility = Visibility.Visible;
            Stop.Visibility = Visibility.Visible;
            Start.Visibility = Visibility.Collapsed;
            Continue.Visibility = Visibility.Collapsed;

            isEvolving = true;
            Game.Evolve(theGrid);
        }

and there is a separate class in which the function Game.Evolve is written (below):

public static void Evolve(Grid[] grid)
        {
            Random random = new Random();

            while (MainWindow.isEvolving)
            {
                Grid square = grid[25];
                square.Background = new SolidColorBrush(Color.FromRgb(Convert.ToByte(random.Next(255)),
                    Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255))));
            }
        }

This is where the infinite loop is created, which causes the program to freeze. If I understand correctly, the implementation of this game requires precisely an infinite loop, so that "Life" can evolve.

I tried creating separate functions that could be stop this one, tried creating coroutines, but if I understand correctly they don't work in WPF, tried creating separate bool variables. None of these options helped. My idea is to have a separate button (below) to stop this loop:

private void Stop_Click(object sender, RoutedEventArgs e)
        {
            Restart.Visibility = Visibility.Collapsed;
            Start.Visibility = Visibility.Collapsed;
            Stop.Visibility = Visibility.Collapsed;
            Continue.Visibility = Visibility.Visible;
            
            isEvolving = false;
        }

but the program just doesn't get to it, because it freezes.


Solution

  • Maybe you can create a task running in another thread.

     private async void Start_Click(object sender, RoutedEventArgs e)
        {
            Restart.Visibility = Visibility.Visible;
            Stop.Visibility = Visibility.Visible;
            Start.Visibility = Visibility.Collapsed;
            Continue.Visibility = Visibility.Collapsed;
            isEvolving = true;
    
            //start a new thead
            await Task.Run(() =>
            {        
                //code in the new thread
                Evolve(theGrid);
            });
    
        }
        public async Task Evolve(Grid[] grid)
        {
            Random random = new Random();
    
            while (MainWindow.isEvolving)
            {
                await Task.Delay(1000); //1sec to slow evolution
    
                //Call the main thread to update UI
                App.Current.Dispatcher.Invoke(() =>
                {
    
                    Grid square = grid[25];
                    square.Background = new SolidColorBrush(Color.FromRgb(Convert.ToByte(random.Next(255)),
                        Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255))));
                });
    
            }
        }
    

    Better do not run a Task at all:

    private async void Start_Click(object sender, RoutedEventArgs e)
    {
        Restart.Visibility = Visibility.Visible;
        Stop.Visibility = Visibility.Visible;
        Start.Visibility = Visibility.Collapsed;
        Continue.Visibility = Visibility.Collapsed;
        isEvolving = true;
    
        await Evolve(theGrid);
    }
    
    public async Task Evolve(Grid[] grid)
    {
        Random random = new Random();
    
        while (MainWindow.isEvolving)
        {
            await Task.Delay(1000); //1sec to slow evolution
    
            Grid square = grid[25];
            square.Background = new SolidColorBrush(Color.FromRgb(Convert.ToByte(random.Next(255)),
            Convert.ToByte(random.Next(255)), Convert.ToByte(random.Next(255))));
        }
    }