WPF кнопки одинаковые / рекомендуемая ширина
Предположим, у вас есть окно с несколькими кнопками, такими как Ok/Cancel или Yes/No/Cancel. Все кнопки должны быть одинаковой ширины. Очевидно, что это можно сделать, просто угадав число и подключив их всех к этому числу.
Есть ли лучший способ сделать это, который бы учитывал предпочтительные / рекомендуемые размеры (насколько широкой должна быть кнопка Ok в любом случае? Это не риторический вопрос, я на самом деле не знаю ответа!), Что нужно по тексту самой длинной надписи, что произойдет, если размер шрифта увеличится и т. д.?
6 ответов
Есть несколько способов сделать это:
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>
РЕДАКТИРОВАТЬ: В реальном коде, вы, вероятно, будете иметь ширину = "Авто". Поскольку другие значения ширины основаны на "основной ширине", следует выбирать кнопку с самой широкой шириной (самый широкий текст).
Другой, возможно, более простой способ сделать это - использовать SharedSizeGroup
собственность на ColumnDefinition
а также RowDefinition
классы.
Столбцы (и строки) в сетке 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>
Используйте "главный" элемент управления, как в ответе Даниэля, но связывайте с атрибутом "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}"/>
В соответствии с Руководством по взаимодействию с пользователем в MS 7 для Windows 7 и Windows Vista (p61) стандартные размеры для командных кнопок составляют фактический размер 50x14 DLU (75x23 пикселей). Рекомендации также предлагают вам "попытаться работать с [этими] значениями ширины и высоты по умолчанию". Очевидно, что если вам нужно больше ширины, чтобы разместить четкую метку, тогда берите больше ширины.
Эти ответы хороши, если у вас есть фиксированное число или фиксированное расположение кнопок, но если вы, как и я, есть динамическое количество кнопок, происходящих из привязки и содержащихся в ItemsControl
тогда это неосуществимо. Но есть простой способ, и он все еще предполагает использование свойства Grid для sharedsize.
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>
Родительский контейнер:
<ItemsControl ItemsSource="{Binding MappingPlugins, ElementName=page}" ItemTemplate="{StaticResource ODIF.Mapping}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Grid.IsSharedSizeScope="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
По сути, содержимое кнопки само по себе может представлять собой Gird, в котором вы можете размещать ярлыки и значки по мере необходимости, но даже при том, что кнопки не находятся в одной и той же сетке (каждая из них является своей), сетка все еще может иметь такой же размер как вы устанавливаете корневой контейнер (ItemsControl
) собственностью Grid.IsSharedSizeScope
к Истине.
Это приведет к тому, что сетка содержимого каждой кнопки будет иметь одинаковый точный размер, основанный на самой большой из них, при этом нет необходимости размещать сами кнопки в предварительно определенной сетке.
В наиболее общем случае вы хотите создать стиль в своем разделе, а затем применить этот стиль по желанию. Теперь, когда вы меняете стиль, меняются все кнопки.
Или вы можете изменить содержимое кнопки, чтобы она автоматически изменяла размер текста.