45

I added a DockPanel to a RadioButton element such that I can distribute the radio button label, a textbox and a button horizontally using 100% of the width.

Using LastChildFill="True"within the DockPanel stretches the last element. This works out nicely if the textbox is the last child in the panel. But, as the button is the last element and has a fixed width, the textbox should be stretched. However, there's no such property like 2ndChildFill="True".

My code looks like this:

    <RadioButton HorizontalAlignment="Stretch"
                                        HorizontalContentAlignment="Stretch">
        <DockPanel >
            <TextBlock VerticalAlignment="Center">in location:</TextBlock>
            <TextBox Grid.Column="1" Margin="10,0,0,0">Path string</TextBox>
            <Button HorizontalAlignment="Right" 
                    Margin="10,0,0,0" Padding="3,0">...</Button>
        </DockPanel>
    </RadioButton>

And it gives me this:

wpf screenshot

Any ideas, hints to fix this? Many thanks in advance...

brgn
  • 1,165
  • 1
  • 9
  • 19
  • 2
    Why don't you use a grid instead? Grid with 3 columns with the second set to * width and the others set to auto – Charleh Dec 25 '12 at 23:25
  • 1
    Yeah, that could work. But it looks a bit overengineered to me though. Wouldn't be DockPanel-Solution a bit more elegant? It doesn't need all this column definitions. – brgn Dec 25 '12 at 23:30

2 Answers2

70

You need to set DockPanel.Dock attached property for your elements and leave TextBox as the last element:

<RadioButton HorizontalAlignment="Stretch"
             HorizontalContentAlignment="Stretch">
    <DockPanel LastChildFill="True">
        <TextBlock DockPanel.Dock="Left"
                   VerticalAlignment="Center"
                   Text="in location:" />
        <Button DockPanel.Dock="Right"
                Margin="10,0,0,0"
                Padding="3,0"
                Content="..." />
        <TextBox Margin="10,0,0,0">
            Path string
        </TextBox>
    </DockPanel>
</RadioButton>
goldenratio
  • 1,026
  • 14
  • 24
max
  • 33,369
  • 7
  • 73
  • 84
  • 4
    The title of question mentioned 'middle', and the answer moves it to 'last'. So why no better answer? – Lei Yang Jan 08 '14 at 09:21
  • 12
    The textbox will still be rendered in the middle, due to the DockPanel.Dock attributes. Moving it to the last position in the XML document just makes WPF grant the control the full remaining space of the parent control. – Nick Pruehs Sep 16 '14 at 14:50
  • 2
    I tried this, but it screws up my taborder! As WPF assigns the default tab index by the order in xaml it would be preferable to not move the element. – aliceraunsbaek May 25 '16 at 16:06
  • 2
    To clarify, `DockPanel` has a property `LastChildFill` that when set to true will expand the last element to fill the remainder of the container. I think the default value for this is `True` (but you can set it to true explicity if you want). – goldenratio Nov 14 '18 at 19:28
4

Accepted answer is fixing your problem but creates another one. If someone uses keyboard (TAB) to navigate through your interface, Button will be focused before TextBox. This could be very annoying on a long run. If you don't want to brake your tab orders use Grid instead of DockPanel:

<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" VerticalAlignment="Center">in location:</TextBlock>
        <TextBox Grid.Column="1" Margin="10,0,0,0">Path string</TextBox>
        <Button Grid.Column="2" HorizontalAlignment="Right" Margin="10,0,0,0" Padding="3,0">...</Button>
    </Grid>
</RadioButton>

Alternative would be to control tab orders yourself using TabIndex attribute. This can be tricky though, especially when you display your control in a collection.

<RadioButton HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" TabIndex="0">
    <DockPanel LastChildFill="True">
        <TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Text="in location:" />
        <Button DockPanel.Dock="Right" Margin="10,0,0,0" Padding="3,0" Content="..." TabIndex="2"/>
        <TextBox Margin="10,0,0,0" TabIndex="1">Path string</TextBox>
    </DockPanel>
</RadioButton>
Pawel
  • 891
  • 1
  • 9
  • 31
  • 1
    I agree, this is a better approach. The other answer is not wrong, but the layout here is more intuitive, as the controls are listed in the order they appear on the UI. Thanks. – Sabuncu Oct 21 '22 at 20:54