Search code examples
c#wpfxaml

Create a grid of controls that share one event handler that can get the button's position


I have a 9 * 9 grid in xaml, that needs contains an 8 * 8 sub grid in the lower right side and a spare row & column to display the sums of each number in the sub grid, represented by a 2d array of class objects (which have a number field) in code behind

I want to create a button control for each slot in the sub grid, ideally in code behind so I don't have to manually write 64 button definitions in xaml code, and would all share one event handler that can get the position of the clicked button

what's the most efficient way to do this?

I know it should look something like this:

 private static void CreateButtons()
 {
     for (int r = 1; r <= 8; r++)
     {
         for (int c = 1; c <= 8; c++)
         {
             // create button in r, c
         }
     }
 }
 private void GridButton_Clicked(object sender, RoutedEventArgs e)
 {
    GridState.SomeMethod(MainGrid[Button Row, Button Column]);
 }

Solution

  • In a situation like you describe, it's pretty easy to configure grids in the code-behind as shown in this minimal example. Buttons will "share an event handler" named AnyButton_Click and the handler can "get the button's position" using Grid.GetColumn(button) and Grid.GetRow(button).

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent(); 
            grid9x9.RowDefinitions.Clear();
            grid9x9.ColumnDefinitions.Clear();
            for (int i = 0; i < 9; i++)
            {
                grid9x9.RowDefinitions.Add(new RowDefinition());
                grid9x9.ColumnDefinitions.Add(new ColumnDefinition());
            }
            int colIndex = 0;
            foreach (var c in columns)
            {
                for (int r = 0; r < 9; r++)
                {
                    if (r == 0 || c == "S")
                    {
                        if ($"{c}{r}" == "S0") continue;
                        var sum = new TextBlock()
                        {
                            Name = $"textBlock{c}{r}",
                            Text = "Sum",
                            TextAlignment = TextAlignment.Center,
                            HorizontalAlignment = HorizontalAlignment.Center,
                            VerticalAlignment = VerticalAlignment.Center,
                            Background = new SolidColorBrush(Colors.Blue),                            
                            Foreground = new SolidColorBrush(Colors.White),
                            Padding = new Thickness(10),
                        };
                        Grid.SetRow(sum, r);
                        Grid.SetColumn(sum, colIndex);
                        grid9x9.Children.Add(sum);
                    }
                    else
                    {
                        var button = new Button
                        {
                            Name = $"button{c}{r}",
                            Content = $"{c}.{r}",
                            HorizontalAlignment = HorizontalAlignment.Stretch,
                            VerticalAlignment = VerticalAlignment.Stretch
                        };
                        // Add the click handler for position
                        button.Click += AnyButton_Click;
                        Grid.SetRow(button, r);
                        Grid.SetColumn(button, colIndex);
                        grid9x9.Children.Add(button);
                    }
                }
                colIndex++;
            }
        }
        private void AnyButton_Click(object sender, RoutedEventArgs e)
        {
            if (sender is Button button)
            {
                MessageBox.Show($"Column: {columns[Grid.GetColumn(button)]} Row: {Grid.GetRow(button)}");
            }
        }
        string[] columns = new[] { "S", "A", "B", "C", "D", "E", "F", "G", "H" };
    }
    

    grid screenshot


    XAML

    <Window x:Class="wpf_grid_9x9_in_code_behind.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:wpf_grid_9x9_in_code_behind"
            mc:Ignorable="d"
            Title="MainWindow" Height="500" Width="800"
            WindowStartupLocation="CenterScreen">
        <Grid 
            Name="grid9x9" 
            HorizontalAlignment="Center"
            Width="450"
            Height="450"/>
    </Window>