WPF: StackPanel with FirstChildFill?

I want a logical and easy way to create a layout with one set of controls to populate, and the rest for the dock. I could use:

<DockPanel LastChildFill="True"> <Button Content="3" DockPanel.Dock="Bottom" /> <Button Content="2" DockPanel.Dock="Bottom" /> <Button Content="1" /> </DockPanel> 

But its not very intuitive. I could also do it like this:

 <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Button Content="1" Grid.Row="0" /> <Button Content="2" Grid.Row="1" /> <Button Content="3" Grid.Row="2" /> </Grid> 

But it is also quite a lot of haml. I really want something like this:

 <StackPanel Fill="None|First|Last"> <Button Content="1" /> <Button Content="2" /> <Button Content="3" /> </StackPanel> 

How can this be achieved if you do not flip the elements, as in the DockPanel, and do not use a fixed number of lines and attached properties, as is the case with the Grid?

+6
c # layout wpf fill
source share
3 answers

You can always write your own panel with various docking rules. You can use the standard DockPanel implementation (available in the source code - it doesn't look very complicated) and create something similar with the rules you prefer. You might even be able to create a class that comes from the DockPanel and overrides ArrangeOverride.

But personally, I would just use the dock panel, which does exactly what you want, except that you do not like its rules, according to which a member becomes a fill.

There is a terrible maintenance problem in the IME grid if you insert / delete rows, thereby endlessly setting row numbers - the DockPanel is much easier in this regard.

Update:

Here you go, I denied you the pleasure of doing it yourself - it's just a cut-out / reverse version of the source code:

 public class BottomDockingPanel : DockPanel { protected override Size ArrangeOverride(Size arrangeSize) { UIElementCollection children = InternalChildren; int totalChildrenCount = children.Count; double accumulatedBottom = 0; for (int i = totalChildrenCount-1; i >=0 ; --i) { UIElement child = children[i]; if (child == null) { continue; } Size childDesiredSize = child.DesiredSize; Rect rcChild = new Rect( 0, 0, Math.Max(0.0, arrangeSize.Width - (0 + (double)0)), Math.Max(0.0, arrangeSize.Height - (0 + accumulatedBottom))); if (i > 0) { accumulatedBottom += childDesiredSize.Height; rcChild.Y = Math.Max(0.0, arrangeSize.Height - accumulatedBottom); rcChild.Height = childDesiredSize.Height; } child.Arrange(rcChild); } return (arrangeSize); } } 
+3
source share

You can use the DockPanel with the StackPanel inside it. The "main" content will be displayed last, not the first, but at least the bottom content will be displayed in a logical order in your XAML. If you want content to be the last, this would be the easiest way.

 <DockPanel LastChildFill="True"> <StackPanel DockPanel.Dock="Bottom"> <Button Content="Bottom 1" /> <Button Content="Bottom 2" /> <Button Content="Bottom 3" /> </StackPanel> <Button Content="Main" /> </DockPanel> 

Or, if you want everything (including filled content) to be displayed in XAML in the same order that it appears on the screen, you can use a Grid with two rows and a StackPanel in the second row. As you pointed out, meshes entail a fair bit of XAML, but the nested StackPanel saves you from adding RowDefinition and Grid.Row for each new element.

 <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Button Grid.Row="0" Content="Main" /> <StackPanel Grid.Row="1"> <Button Content="Bottom 1" /> <Button Content="Bottom 2" /> <Button Content="Bottom 3" /> </StackPanel> </Grid> 
+1
source share

There is no panel in WPF that supports this out of the box. If you need this specific behavior, you can create your own panel, but I would not advise you to do this because it is quite ordinary and not needed so often (what if you want a panel that has a behavior like MiddleChildFill ? your own panel for this case too?).

Usually this kind of layout is achieved using the Grid (as you mentioned). Yes, it is true that Grid has a very detailed syntax (you can simplify it with a helper like this ), but it gives you a lot of flexibility. And at the end of the day, this is what matters.

0
source share

All Articles