开发者

WPF buttons same/recommended width

Suppose you have a window with multiple buttons such as Ok/Cancel or Yes/No/Cancel. All the buttons need to be the same width. Obviously this could be done by just guessing a number and hardwiring all of them to that number.

I开发者_Go百科s there a better way to do it, one that would take into account preferred/recommended sizes (just how wide should an Ok button be anyway? This is not a rhetorical question, I actually don't know the answer!), what's needed by the text of the longest caption, what happens if the font size is increased etc?


Another, perhaps simpler, way to do this is to use the SharedSizeGroup property on the ColumnDefinition and RowDefinition classes.

Columns (and Rows) in a WPF Grid can automatically resize to fit their contents - when SharedSizeGroup is used, columns with the same group name share their resizing logic.

The Xaml would look something like this ...

<Grid Grid.IsSharedSizeScope="True">

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition SharedSizeGroup="Buttons" />
        <ColumnDefinition SharedSizeGroup="Buttons" />
        <ColumnDefinition SharedSizeGroup="Buttons" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <Button Grid.Column="1"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Center"
            Content="Ok"
            Margin="4" />

    <Button Grid.Column="2"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Center"
            Content="Cancel"
            Margin="4" />

    <Button Grid.Column="3"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Center"
            Content="Long Button Caption"
            Margin="4" />
</Grid>


There are several ways to do this:

1) Use a Grid for layout. Each Button gets its own Column, which is Star-sized. That way, all columns are the same size:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Button Grid.Column="0">Yes</Button>
    <Button Grid.Column="1">No</Button>
    <Button Grid.Column="2">Cancel</Button>
</Grid>

2) You can have one item as "master size" and bind the width of all others to this item's width.

<StackPanel Orientation="Horizontal">
    <Button Name="MasterButton" Width="100">Yes</Button>
    <Button>
        <Button.Width>
            <Binding ElementName="MasterButton" Path="Width"/>
        </Button.Width>
        No
    </Button>
</StackPanel>

EDIT: In actual code, you probably will have Width="Auto". Since the other widths are based on the "master width", the button with the widest width (widest text) should be chosen.


Use a "master" control, like in Daniel's answer, but bind to the "ActualWidth" attribute instead of "Width":

<StackPanel Orientation="Horizontal">
    <Button Name="MasterButton">Yes</Button>
    <Button>
        <Button.Width>
            <Binding ElementName="MasterButton" Path="ActualWidth"/>
        </Button.Width>
        No
    </Button>
</StackPanel>

This way, the value is taken from the master control at run time, after minimum and maximum width and all other layout calculations have been taken into account. Binding to "Width" binds to whatever you happen to put into the attribute at compile time, which may not be the width that is really used.

Also, the binding can be written shorter like

<Button Width="{Binding ElementName=MasterButton, Path=ActualWidth}"/>


According to the MS User Experience Interaction Guidelines for Windows 7 and Windows Vista (p61), standard dimensions for command buttons are 50x14 DLU actual size (75x23 pixels). The guidelines further suggest you "try to work with [these] default widths and heights." Obviously, if you need more width to fit a clear label, then take more width.


These answers are great if you have a fixed number or fixed layout for the buttons, but if like me there is a dynamic number of buttons coming from a binding and contained in a ItemsControl then this is not feasible. But there is a simple way and it still involves used the sharedsize property of Grid.

DataTemplate:

<DataTemplate x:Key="ODIF.Mapping">
    <Button HorizontalContentAlignment="Left" Background="#FFEEEEEE" BorderBrush="#FFBDBDBD">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" SharedSizeGroup="PluginButtonsWidth"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" SharedSizeGroup="PluginButtonsIconHeight"/>
                <RowDefinition Height="Auto" SharedSizeGroup="PluginButtonsNameHeight"/>
            </Grid.RowDefinitions>
            <Image Width="32" Height="32" Source="{Binding PluginIcon}" RenderOptions.BitmapScalingMode="HighQuality"/>
            <TextBlock Grid.Row="1" Text="{Binding PluginName}"/>
        </Grid>
    </Button>
</DataTemplate>

Parent container:

<ItemsControl ItemsSource="{Binding MappingPlugins, ElementName=page}" ItemTemplate="{StaticResource ODIF.Mapping}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Grid.IsSharedSizeScope="True"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

Essentially the button's content can itself be a Gird which then you can place your labels and icons as needed in, but even though the buttons do not reside in the same grid (they each are their own) the grid can still share it size so long as you set the root container's (ItemsControl) property of Grid.IsSharedSizeScope to True.

This will force the content grid of each button to be the same exact size based on the largest one while not having to have the Buttons themselves in a predefined grid.


In the most general case, you want to create a Style in your section, then apply this style as desired. Now when you change the style, all buttons change.

Or you can change the Content of the button so that it autosizes to the text.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜