1

I'm just starting a new WPF app. I have a grid and want to create the rows dynamically (pressing a button for example) and then create TextView/ProgressBar inside this row.

I already searched how to create the gridrows programatically. But in every solution, i can't access what's inside and it becomes useless.

<Grid x:Name="MainGrid">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Button x:Name="AddLineButton" Content="Click to add a new line" Click="AddLineButton_Click"/>
    <Grid x:Name="beGrid" Grid.Row="1">
<!-- I need my new rows here -->
    </Grid>
</Grid>
int i = 0; //nb of rows

    private void AddLineButton_Click(object sender, RoutedEventArgs e)
    {
        Create_line();
        i++;
    }

    private void Create_line()
    {
        RowDefinition gridRow = new RowDefinition();
        gridRow.Height = new GridLength(1, GridUnitType.Star);
        beGrid.RowDefinitions.Add(gridRow);
        StackPanel stack = new StackPanel();
        stack.Orientation = Orientation.Horizontal;
        TextBlock textBlock = new TextBlock();
        textBlock.Text = "Question";
        textBlock.Name = "Test" + i.ToString();
        stack.Children.Add(textBlock);
        beGrid.Children.Add(stack);
        Grid.SetRow(stack, i);
    }

I can't access a previously created element.

AFTER ANSWER :

    private void Create_line()
    {
        RowDefinition gridRow = new RowDefinition();
        gridRow.Height = new GridLength(1, GridUnitType.Star);
        beGrid.RowDefinitions.Add(gridRow);
        StackPanel stack = new StackPanel();
        stack.Orientation = Orientation.Horizontal;
        TextBlock textBlock = new TextBlock();
        textBlock.Text = "Question";
        textBlock.Name = "Test" + i.ToString();
        RegisterName(textBlock.Name, textBlock);
        stack.Children.Add(textBlock);
        beGrid.Children.Add(stack);
        Grid.SetRow(stack, i);
    }

To get the created TextBlock : var text = (TextBlock)FindName("Test"+i.ToString());

Ben
  • 55
  • 1
  • 6

2 Answers2

1

you can store all created StackPanel in a List.

private void AddLineButton_Click(object sender, RoutedEventArgs e)
{
    Create_line();
}

List<StackPanel> items;

private void Create_line()
{
    RowDefinition gridRow = new RowDefinition();
    gridRow.Height = new GridLength(1, GridUnitType.Star);
    beGrid.RowDefinitions.Add(gridRow);

    StackPanel stack = new StackPanel();
    stack.Orientation = Orientation.Horizontal;

    int i = items.Count + 1;
    TextBlock textBlock = new TextBlock();
    textBlock.Text = "Question";
    textBlock.Name = "Test" + i.ToString();

    stack.Children.Add(textBlock);
    beGrid.Children.Add(stack);
    Grid.SetRow(stack, items.Count);

    items.Add(stack);
}

you can access any previos panel by index, e.g. items[0], and get elements from Children property: items[0].Children[0] as TextBlock

ASh
  • 34,632
  • 9
  • 60
  • 82
  • Thanks, I made a little modification of what you said (see edit), I'm using `RegisterName()`. Thanks for the quick answer ! :) – Ben Aug 27 '19 at 13:17
1

Creating controls manually like this is really not the WPF way ...

The best methodology is to define an item class that holds properties for each value that you want to display / edit.

Then create an ObservableCollection (since you will be manually adding items on a button click) of these items within your Window, and set this as the ItemsSource property of an ItemsControl control. A DataTemplate is used to define the exact controls to display each item within the control, which will bind to the properties of the item.

Peregrine
  • 4,287
  • 3
  • 17
  • 34