Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In WPF, is there a way to make a StackPanel with aligned columns like a Grid?

For example I could do something like this:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Width="Auto">
        <RowDefinition Width="Auto">
        <RowDefinition Width="Auto">
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0">Header 1</TextBlock>
    <TextBox Grid.Row="0" Grid.Column="1" MaxLines="1" />
    <Button Grid.Row="0" Grid.Column="2">Send</Button>
    <Button Grid.Row="0" Grid.Column="3">Save</Button>
    <TextBlock Grid.Row="1" Grid.Column="0">Header 2</TextBlock>
    <TextBox Grid.Row="1" Grid.Column="1" MaxLines="1" />
    <Button Grid.Row="1" Grid.Column="2">Send</Button>
    <Button Grid.Row="1" Grid.Column="3">Save</Button>
    <TextBlock Grid.Row="2" Grid.Column="0">Header 3</TextBlock>
    <TextBox Grid.Row="2" Grid.Column="1" MaxLines="1" />
    <Button Grid.Row="2" Grid.Column="2">Send</Button>
    <Button Grid.Row="2" Grid.Column="3">Save</Button>
</Grid>

Or I could do something like this:

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Header 1</TextBlock>
        <TextBox MaxLines="1" />
        <Button>Send</Button>
        <Button>Save</Button>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Header 2</TextBlock>
        <TextBox MaxLines="1" />
        <Button>Send</Button>
        <Button>Save</Button>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
        <TextBlock>Header 3</TextBlock>
        <TextBox MaxLines="1" />
        <Button>Send</Button>
        <Button>Save</Button>
    </StackPanel>
<StackPanel>

Except that I want to be able to easily manipulate the rows (add new rows, move rows around, etc.) just like in the StackPanel, while keeping the columns aligned properly just like in the Grid.

like image 381
Matt Avatar asked Aug 29 '12 12:08

Matt


2 Answers

You could use many one-row Grids with size sharing on the columns. It gets verbose when done without any controls, so you could encapsulate some logic (like creating columns and assigning Grid.Column) in a derivative of ItemsControl or an attached property for example.

like image 180
H.B. Avatar answered Sep 19 '22 16:09

H.B.


Here's a class I just threw together for approximately the same purpose - essentially I wanted to be able to put a bunch of labels in the left column and values of different types (text box, dropdown, etc) on the right.

It only has two columns, but it could be adapted to different numbers.

public class LabelValueGrid : Grid
{
    public LabelValueGrid()
        : base()
    {
        ColumnDefinitions.Add(new ColumnDefinition());
        ColumnDefinitions.Add(new ColumnDefinition());
        ColumnDefinitions[0].Width = new System.Windows.GridLength(1, System.Windows.GridUnitType.Auto);
        ColumnDefinitions[1].Width = new System.Windows.GridLength(1, System.Windows.GridUnitType.Star);
    }

    protected override void OnVisualChildrenChanged(System.Windows.DependencyObject visualAdded, System.Windows.DependencyObject visualRemoved)
    {
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);

        int curRow = -1;
        int curCol = 1;

        RowDefinitions.Clear();

        if (Children != null)
            foreach (System.Windows.UIElement curChild in Children)
            {
                if (curCol == 0)
                    curCol = 1;
                else
                {
                    curCol = 0;
                    curRow++;
                    RowDefinitions.Add(new RowDefinition() {Height = new System.Windows.GridLength(1, System.Windows.GridUnitType.Auto)});
                }

                Grid.SetRow(curChild, curRow);
                Grid.SetColumn(curChild, curCol);
            }

        RowDefinitions.Add(new RowDefinition() {Height = new System.Windows.GridLength(1, System.Windows.GridUnitType.Star)});
    }
}

I can use this like a grid, except I just list the controls and then it alternates the columns automatically:

<local:LabelValueGrid>
    <TextBlock Text="Label1"/>
    <TextBox Name="value1"/>
    <TextBlock Text="Label2"/>
    <TextBox Name="value2"/>
</local:LabelValueGrid>
like image 20
Overlord Zurg Avatar answered Sep 19 '22 16:09

Overlord Zurg