37

Imagine I have two WPF buttons on a window, with content as follows:

<Button>OK</Button>
<Button>Cancel</Button>

I want these buttons to be the same width, however in a scenario where the Content is bound to a localised value for a given user's language, I don't know how wide the buttons need to be to accommodate the new content.

How might I apply a minimum width to these buttons, such that the width of the widest one (according to content) is effectively used as the MinWidth of both, thus keeping them uniform?

Or to put it another way: I don't want the buttons to be the width of their container (unless using a container in a clever way is the answer to my problem), and I don't want them each to just size to their own content because that will make them different sizes. I want something in-between. The one with the largest content to size to display it's content, and all others to size to that same width, so the widths are all equal.

I expect the answer lies in putting them in some sort of container. I know I could use a Grid and let them fill grid "cells", but the point is I don't want them to be too wide, either. I know I could have some code-behind that runs on the Content_Changed event of the buttons and sets the minwidth to that of the widest button, but I'm interested in a pure-xaml method. It might be I need to create a custom control extending ItemsControl that rusn code-behind when new items are added or re-sized and applies the width of the widest item as the MinWidth of all the other items.

Many thanks in advance.

H.B.
  • 166,899
  • 29
  • 327
  • 400
Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • So you are saying you don't want to use the and set the Buttons Width="Auto"? – Willem Jun 06 '11 at 09:45
  • I don't want the buttons to be the width of their container (unless using a container in a clever way is the answer to my problem), and I don't want them to size to their content because that will make them different sizes. I want something in-between. The one with the largest content to size to display it's content, and all others to size to that same amount, so the widths are all equal. – Neil Barnwell Jun 06 '11 at 09:59
  • So then i guess your buttons are all scattered on your view, because if not, and their all grouped, then the ColumnDefinition will do the trick. If their all scattered, i would also like to know a good solution for your problem. =) – Willem Jun 06 '11 at 10:10
  • No, they were in a horizontally-aligned stackpanel, in a classic "OK", "Cancel" design. I think H.B.'s answer below (http://stackoverflow.com/questions/6249946/wpf-evenly-sized-buttons-according-to-content-of-largest-button/6250568#6250568) actually is what you said, I just hadn't really grasped properly from your comment what you meant. :) – Neil Barnwell Jun 06 '11 at 11:21
  • @Willem `` needed not `"Auto"`. – Tom Wilson May 08 '17 at 13:13

3 Answers3

24

The Grid

  <Grid HorizontalAlignment="Right" Grid.IsSharedSizeScope="true">
    <Grid.ColumnDefinitions>
        <ColumnDefinition SharedSizeGroup="A"/>
        <ColumnDefinition SharedSizeGroup="A"/>
    </Grid.ColumnDefinitions>
    <Grid.Children>
        <Button Grid.Column="0" Content="OK"/>
        <Button Grid.Column="1" Content="Cancel"/>
    </Grid.Children>
  </Grid>

This can be broken up, you just need to set the IsSharedSizeScope on a common ancestor, e.g.:

    <StackPanel Grid.IsSharedSizeScope="true">
        <Grid HorizontalAlignment="Right">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="A"/>
            </Grid.ColumnDefinitions>
            <Grid.Children>
                <Button Grid.Column="0" Content="OK"/>
            </Grid.Children>
        </Grid>
        <!-- ... -->
        <Grid HorizontalAlignment="Left">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="A"/>
            </Grid.ColumnDefinitions>
            <Grid.Children>
                <Button Grid.Column="0" Content="Cancel"/>
            </Grid.Children>
        </Grid>
    </StackPanel>

To prevent the buttons from becoming too large change the HorizontalAlignment of the Grid to something else than Stretch or set a MaxWidth.

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • The way you showed which using SharedSizeGroup I think is more useful than the answer accepted by the author.Thank you. – Melon NG May 26 '18 at 23:54
22
Use UniformGrid

<UniformGrid HorizontalAlignment="Right" Rows="1" Columns="2">
  <Button Content="Ok" Grid.Column="0"/>
  <Button Content="Cancel" Grid.Column="1"/>
</UniformGrid>
Amir Touitou
  • 3,141
  • 1
  • 35
  • 31
  • 2
    This answer has the advantage of allowing you to set Visibility = "Collapsed" for buttons that you don't want and the entire cell disappears - doing that with a SharedSizeGroup grid leaves you with a hole, which might not be what you want. Plus its terser! – Wolfshead Jun 24 '16 at 07:25
  • 2
    `Grid.Column` and `Grid.Row` are ignored by `UniformGrid`, controls are added in order of declaration in Xaml. – Gerard Feb 16 '19 at 22:36
0

I like using a wrap panel for this type of scenario. When it's loaded I get the max width from all children using linq. (assuming children are all buttons)

xaml

<WrapPanel Name="WP_ButtonSelections" Orientation="Horizontal" HorizontalAlignment="Center" Loaded="WP_ButtonSelections_Loaded"></WrapPanel>

cs

WP_ButtonSelections.Children.Add(new Button() { Content = "Hello" });
WP_ButtonSelections.Children.Add(new Button() { Content = "Hello World" });


private void WP_ButtonSelections_Loaded(object sender, RoutedEventArgs e)
{
   double maxWidth = WP_ButtonSelections.Children.OfType<FrameworkElement>().Max(elm => elm.ActualWidth);
   WP_ButtonSelections.Children.OfType<FrameworkElement>().ToList().ForEach(elm => elm.Width = maxWidth);
}

I needed a programmatic solution. This requires the loaded event because programmatically added buttons wont have an ActualWidth defined upon calling WP_ButtonSelections.Children.Add(). This solution should work with xaml defined buttons, or a mixture of both xaml and programmatic.

clamchoda
  • 4,411
  • 2
  • 36
  • 74