WPF按钮相同/推荐宽度

11
假设您有一个带有多个按钮的窗口,例如“确定/取消”或“是/否/取消”。 所有按钮需要具有相同的宽度。 显然,这可以通过猜测一个数字并将所有按钮硬连接到该数字来完成。
是否有更好的方法来实现它?一个考虑了首选/推荐大小的方法(“确定”按钮应该有多宽呢? 这不是个反问句,我真的不知道答案!),最长标题所需的文本,如果字体大小增加会发生什么等?

请尽量不要硬编码UI大小等内容。考虑到国际化和(现在WPF使用“分辨率无关单位”后)各种大小和DPI屏幕,这是一种不好的做法。我们有可用的布局面板来使用。它们很好。 - Benny Jobigan
按钮应该是50dlu x 23dlu大小。WPF不支持对话框单位;所以你会遇到困难。 - Ian Boyd
6个回答

12

另一种可能更简单的方法是使用SharedSizeGroup属性,它位于ColumnDefinitionRowDefinition类中。

在WPF网格中,列(和行)可以自动调整大小以适应其内容。当使用SharedSizeGroup时,具有相同组名的列共享其调整逻辑。

Xaml代码如下...

<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>

9

有几种方法可以实现这个目标:

1)使用网格布局。每个按钮都有自己的列,大小为星号大小。这样,所有列的大小都相同:

<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) 您可以将一个项目设置为 "主尺寸",并将其他所有项目的宽度绑定到此项目的宽度。

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

编辑: 实际代码中,你可能会看到Width="Auto"。由于其他宽度都是基于“主要宽度”而设定的,所以应该选择具有最宽宽度(最宽文本)的按钮。


+1 推荐在您的第一个建议中使用面板,但我非常反对硬编码UI尺寸。 - Benny Jobigan
在第二种情况下,这是为了演示绑定是否正常工作。 - Daniel Rose
具有最宽文本的按钮在不同语言中可能是不可预测的。是否有任何方法可以使所有按钮具有相同的宽度,以便最长的文本决定它是哪个按钮,而不管是哪个按钮? - Andrew Arnott
1
在这种情况下,请使用网格布局,就像我回答的第一个变体或Bevan的回答一样。 - Daniel Rose
是的,我选择了Bevan的答案,因为这样可以使所有按钮具有相同的宽度,而不需要假定对话框或最宽的按钮的全宽。 - Andrew Arnott

5
使用类似于Daniel的答案中的“主”控件,但绑定到“ActualWidth”属性而不是“Width”:
<StackPanel Orientation="Horizontal">
    <Button Name="MasterButton">Yes</Button>
    <Button>
        <Button.Width>
            <Binding ElementName="MasterButton" Path="ActualWidth"/>
        </Button.Width>
        No
    </Button>
</StackPanel>

这种方式,在运行时从主控制获取值,在考虑最小和最大宽度以及所有其他布局计算之后。绑定到“宽度”会绑定到在编译时放入属性中的任何内容,这可能不是实际使用的宽度。

此外,绑定可以更简短地书写,如下:

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

2
根据Windows 7和Windows Vista的MS用户体验交互指南(第61页),命令按钮的标准尺寸为50x14 DLU实际大小为75x23像素。该指南进一步建议您“尝试使用[这些]默认宽度和高度”。显然,如果需要更多宽度来适应清晰的标签,则需要取得更多宽度。

按钮应该是50x14个对话框单位。你的像素转换是错误的;至少在我使用“Georgia 14pt”的电脑上是这样。这就是为什么存在对话框单位 - 以便人们停止使用像素大小。 - Ian Boyd

1
这些答案对于有固定数量或布局的按钮非常好,但如果像我一样,有一个来自绑定并包含在ItemsControl中的动态按钮数量,则这不可行。但是有一种简单的方法,它仍然涉及使用Grid的sharedsize属性。
数据模板:
<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>

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

基本上,按钮的内容本身可以是一个网格,然后您可以根据需要放置标签和图标,但即使按钮不驻留在同一个网格中(它们各自拥有自己的网格),只要将根容器(ItemsControl)的Grid.IsSharedSizeScope属性设置为True,网格仍然可以共享其大小。

这将强制每个按钮的内容网格具有相同的确切大小,基于最大值,而无需将按钮本身放入预定义的网格中。


0
在最一般的情况下,您想要在您的
中创建一个样式,然后根据需要应用此样式。现在当您更改样式时,所有按钮都会更改。
或者,您可以更改按钮的内容,使其自动调整大小以适应文本。

谢谢。但是,如果我错了,请纠正我,将按钮自适应文本大小,不会违反所有按钮宽度相同的要求吗?而且,样式解决方案,只是一种实现“猜一个数字并将所有按钮硬连到该数字”的特定方式,对吗? - rwallace
啊... 我现在明白您的要求了,抱歉!那么丹尼尔有一个更好的答案。 - Dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接