gaw
gaw

Reputation: 157

Create StackPanels dynamically and refer to any of them in code behind

In its simplest form...

I would like to create as many StackPanels as I want and then add Rectangles in them. Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.

Any help would be appreciated.

For example, if our favorite beer wrote the framework I could do it like this:

XAML:

<Page
    x:Class="Test2.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Test2"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <Button Name="StartButton" Content="Start" Click="StartButton_Click" Height="30" Width="200" Margin="5"/>
        </StackPanel>

        <StackPanel Grid.Row="1" Name="myStackPanel" VerticalAlignment="Top"/>

    </Grid>
</Page>

Code Behind:

namespace Test2
{
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();

            for (var i = 0; i < 5; i++) // The 5 here could be any number
            {
                myStackPanel.Children.Add(new StackPanel
                {
                    Name = "myPanel" + i,
                    Orientation = Orientation.Horizontal
                });

                for (var j = 0; j < 10; j++) // The 10 here could be any number
                {
                    ("myPanel" + i).Children.Add(new Rectangle
                    {
                        Name = "myRectangle" + i + "-" + j,
                        Fill = new SolidColorBrush(Colors.Black),
                        Width = 20,
                        Height = 20,
                        Margin = new Thickness(1)
                    });
                }
            }
        }

        private void StartButton_Click(object sender, RoutedEventArgs e)
        {
            // E.G. To change the Fill color of Rectangle4 in StackPanel2

            ("myRectangle" + 2 + "-" + 4).Fill = new SolidColorBrush(Colors.Red);
        }
    }
}

Upvotes: 3

Views: 10779

Answers (2)

brunnerh
brunnerh

Reputation: 184526

That is not how you approach this in WPF, at all.

You usually do not concern yourself with any UI components but only the data. In this case you data bind an ItemsControl to a list of rows, each row containing a list of cells. In the ItemsControl definition you then set an ItemTemplate that contains another ItemsControl binding to the cells. In the nested ItemsControl you then can set an ItemTemplate where you bind the Background to a (notifying) property of your cells which you then just need to change in code.

Check out these overviews:

You may also want to look into the Model-View-ViewModel pattern to ensure a suitable application architecture.

Upvotes: 2

Franklin Chen - MSFT
Franklin Chen - MSFT

Reputation: 4923

Firstly, to add Rectangle shapes, we can create an instance of StackPanel and manipulate its Children elements:

for (var i = 0; i < 5; i++) // The 5 here could be any number
{
                StackPanel sp = new StackPanel
                {
                    Name = "myPanel" + i,
                    Orientation = Orientation.Horizontal
                };
                myStackPanel.Children.Add(sp);

                for (var j = 0; j < 10; j++) // The 10 here could be any number
                {
                    sp.Children.Add(new Rectangle
                    {
                        Name = "myRectangle" + i + "-" + j,
                        Fill = new SolidColorBrush(Colors.Black),
                        Width = 20,
                        Height = 20,
                        Margin = new Thickness(1)
                    });
                }
}

Then to be able to change the Fill color of any one of the Rectangles when I click the Start Button for instance. All in Code Behind.

As tgpdyk mentioned, we need to use VisualTreeHelper to find the specified rectangle shape.

Helper class:

public static class FrameworkElementExtensions
{
        public static T TraverseCTFindShape<T>(DependencyObject root, String name) where T : Windows.UI.Xaml.Shapes.Shape
        {
            T control = null;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(root); i++)
            {
                var child = VisualTreeHelper.GetChild(root, i);

                string childName = child.GetValue(FrameworkElement.NameProperty) as string;
                control = child as T;

                if (childName == name)
                {
                    return control;
                }
                else
                {
                    control = TraverseCTFindShape<T>(child, name);

                    if (control != null)
                    {
                        return control;
                    }
                }
            }

            return control;
        }
}

How to use it:

private void StartButton_Click(object sender, RoutedEventArgs e)
{
            // E.G. To change the Fill color of Rectangle4 in StackPanel2
            var rec = FrameworkElementExtensions.TraverseCTFindShape<Shape>(myStackPanel, "myRectangle" + 2 + "-" + 4);
            rec.Fill = new SolidColorBrush(Colors.Red);
}

enter image description here

I've uploaded my sample to Github repository

Upvotes: 6

Related Questions