我目前在StackPanel
内有多个Button
。
Button
的内容是动态的,所以我不知道它们的大小。
每个Button
都有不同的边距。
我想让所有按钮具有相同的宽度(不计算其中的边距)。
以下是一个例子:
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Margin="3" Content="{Binding PreviousButtonText, ElementName=CurrentControl}" Command="{Binding GoToPreviousPageCommand}"/>
<Button Margin="3,3,8,3" Content="{Binding NextButtonText, ElementName=CurrentControl}" Command="{Binding GoToNextPageCommand}" Visibility="{Binding IsLastPage, Converter={StaticResource BooleanToVisibleConverter}, ConverterParameter=true, UpdateSourceTrigger=PropertyChanged}"/>
<Button Margin="3,3,8,3" Content="{Binding FinishButtonText, ElementName=CurrentControl}" Command="{Binding FinishCommand}" Visibility="{Binding IsLastPage, Converter={StaticResource BooleanToVisibleConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Button Margin="8,3,3,3" Content="{Binding CancelButtonText, ElementName=CurrentControl}" Command="{Binding CancelCommand}"/>
</StackPanel>
由于我需要具有相同的宽度,但不计算其中的边距,我不能使用UniformGrid
(或者SharedSizeGroup
的网格。)
目标是让所有按钮占据其中一个按钮所需的“最大宽度”。
这必须在XAML中完成,没有代码。 另外,按钮内的文本可以在运行时更改。
知道怎么做吗?
编辑似乎很多人都不明白我需要一个宽度相同的按钮,而不是按钮+他的边距相同的宽度。
答案 0 :(得分:3)
这是一个继承标准WPF Button控件的小类。它确保当任何按钮改变其大小并成为具有最大宽度的按钮时,同一容器内的控件共享相同的宽度。
但是,这只是一个概念的原则,您应该根据容器(可能不仅仅是StackPanels)来完成它,也许可以用异常处理错误,而不是return;
语句等等。
稍后编辑:您指定不应该在此处使用代码隐藏解决方案。您的要求是否也禁止新的控制类?如果是,那么这不适用。
internal class WidthButton : Button
{
private static Dictionary<Panel, List<Button>> _containers = new Dictionary<Panel, List<Button>>();
public WidthButton()
{
this.Initialized += WidthButton_Initialized;
this.SizeChanged += WidthButton_SizeChanged;
}
void WidthButton_Initialized(object sender, EventArgs e)
{
var parent = VisualTreeHelper.GetParent(this) as Panel;
if (parent == null) return;
var thisButton = sender as Button;
if (thisButton == null) return;
if (!_containers.ContainsKey(parent))
{
_containers.Add(parent, new List<Button>());
}
if (!_containers[parent].Contains(thisButton))
{
_containers[parent].Add(thisButton);
}
}
void WidthButton_SizeChanged(object sender, System.Windows.SizeChangedEventArgs e)
{
var thisButton = sender as Button;
if (thisButton == null) return;
var containerPair = _containers.FirstOrDefault(pair => pair.Value.Contains(thisButton));
if (containerPair.Value == null) return;
var maxWidth = containerPair.Value.Max(btn => btn.ActualWidth);
containerPair.Value.ForEach(btn => btn.Width = maxWidth);
}
}
稍后编辑:这是一个使用附加行为的示例(潜在的内存泄漏,因为没有取消订阅SizeChanged事件)
internal class WidthBehavior
{
private static Dictionary<string, List<FrameworkElement>> _scopes = new Dictionary<string, List<FrameworkElement>>();
public static readonly DependencyProperty WidthShareScopeProperty = DependencyProperty.RegisterAttached(
"WidthShareScope", typeof (string), typeof (WidthBehavior), new PropertyMetadata(default(string), PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var elem = dependencyObject as FrameworkElement;
if (elem == null) return;
var scope = dependencyPropertyChangedEventArgs.NewValue as string;
if (scope == null) return;
if (!_scopes.ContainsKey(scope))
{
_scopes.Add(scope, new List<FrameworkElement>());
}
if (!_scopes[scope].Contains(elem))
{
_scopes[scope].Add(elem);
elem.SizeChanged += elem_SizeChanged;
}
}
static void elem_SizeChanged(object sender, SizeChangedEventArgs e)
{
var elem = sender as FrameworkElement;
if (elem == null) return;
var scope = GetWidthShareScope(elem);
ArrangeScope(scope);
}
private static void ArrangeScope(string scope)
{
if (!_scopes.ContainsKey(scope)) return;
var list = _scopes[scope];
var maxWidth = list.Max(elem => elem.ActualWidth);
list.ForEach(elem => elem.Width = maxWidth);
}
public static void SetWidthShareScope(DependencyObject element, string value)
{
element.SetValue(WidthShareScopeProperty, value);
}
public static string GetWidthShareScope(DependencyObject element)
{
return (string) element.GetValue(WidthShareScopeProperty);
}
}
你可以像这样使用它:
<StackPanel Orientation="Horizontal">
<Button Margin="10 15 13 12"
behavior:WidthBehavior.WidthShareScope="Scope1"
Content="Text"/>
<Button Margin="7 2 14 11"
behavior:WidthBehavior.WidthShareScope="Scope1"
Content="Longer Text"/>
</StackPanel>
答案 1 :(得分:1)
或者,您也可以使用UniformGrid
。只需将UniformGrid.Rows
设置为1
即可实现Orientation="Horizontal"
的相同行为:
<UniformGrid Rows="1" HorizontalAlignment="Right">
<Button Margin="3" Content="{Binding PreviousButtonText, ElementName=CurrentControl}" Command="{Binding GoToPreviousPageCommand}"/>
<Button Margin="3,3,8,3" Content="{Binding NextButtonText, ElementName=CurrentControl}" Command="{Binding GoToNextPageCommand}" Visibility="{Binding IsLastPage, Converter={StaticResource BooleanToVisibleConverter}, ConverterParameter=true, UpdateSourceTrigger=PropertyChanged}"/>
<Button Margin="3,3,8,3" Content="{Binding FinishButtonText, ElementName=CurrentControl}" Command="{Binding FinishCommand}" Visibility="{Binding IsLastPage, Converter={StaticResource BooleanToVisibleConverter}, UpdateSourceTrigger=PropertyChanged}"/>
<Button Margin="8,3,3,3" Content="{Binding CancelButtonText, ElementName=CurrentControl}" Command="{Binding CancelCommand}"/>
</UniformGrid>
答案 2 :(得分:1)
在这种情况下,您想要为某些属性width属性共享相同的值吗?为它创造风格:
<Style x:Key="DialogButton" BaseOn="{StaticResource YourDefaultButtonStyle}">
<Setter Property="Width" Value="100" />
</Style>
或者使用一些布局面板,例如Grid:
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedColumnSize="Button"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto" SharedColumnSize="Button"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="Auto" SharedColumnSize="Button"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Margin="0" />
<Button Grid.Column="2" Margin="0" />
<Button Grid.Column="4" Margin="0" />
</Grid>
编辑:还有一个建议: 如果你的按钮在整个应用程序中具有相同的宽度,如果可能的话,这不仅仅是单个视图,这很好。创建指定MinWidth的显式样式。
<Style x:Key="DialogButton" BaseOn="{StaticResource YourDefaultButtonStyle}">
<Setter Property="MinWidth" Value="100" />
</Style>
具有此样式的所有按钮将具有相同的宽度,但文本超出最小宽度。这就是大多数对话框中按钮的工作方式(例如,在Visual Studio选项对话框,保存对话框等中。)
答案 3 :(得分:0)
使用隐式风格?
但是你需要知道哪个Button有最大宽度并将其绑定到样式。
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="{Binding ButtonMaxWidth}"/>
</Style>
</StackPanel.Resources>
<Button Margin="3" Content="11" />
<Button Margin="3,3,8,3" Content="2222" />
<Button Margin="3,3,8,3" Content="333333" />
<Button Margin="8,3,3,3" Content="44444444" />
</StackPanel>
答案 4 :(得分:0)
当我遇到Margin
/ Padding
问题时,我更喜欢使用一个封闭的控制元素来独立于原始控件来处理它。一种解决方案是模仿Margin
,Border
没有厚度,没有画笔,Padding
具有所需的保证金。
然后,如果以下解决方案,您必须事先知道哪个Button
将具有最大宽度。因为我们需要将此ActualWidth
的{{1}}复制到所有其他Button
。
Width