[英]WPF: Ensure that button have the same Width
我目前有一個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
Grid)。
目標是使所有按鈕占據其中一個按鈕所需的“最大寬度”。
這必須在XAML中完成,沒有任何代碼。 另一件事,可以在運行時更改按鈕內的文本。
任何想法如何做到這一點?
編輯似乎很多人不理解我需要一個具有相同寬度的按鈕,而不是一個具有相同寬度的按鈕和頁邊距。
這是一個繼承標准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>
或者,您也可以使用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>
您是否要為某些屬性(在這種情況下為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“選項”對話框,“保存”對話框等中。)
使用隱式樣式?
但是,您需要知道哪個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>
當我遇到Margin
/ Padding
問題時,我更喜歡有一個封閉的控件元素來獨立於原始控件進行處理。 一個解決辦法是imitiate的Margin
與Border
沒有厚度,沒有電刷和Padding
具有所需保證金。
然后,如果采用以下解決方案,則必須事先知道哪個Button
具有最大寬度。 因為我們需要將此Button
的ActualWidth
復制到所有其他Button
的Width
。
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Border BorderBrush="Transparent"
BorderThickness="0"
Padding="3">
<Button x:Name="MaxWidthButton"
Content="{Binding Path=PreviousButtonText, FallbackValue=VeryLongTextThatIKnowItsLength}" />
</Border>
<Border BorderBrush="Transparent"
BorderThickness="0"
Padding="3,3,8,3">
<Button Width="{Binding ElementName=MaxWidthButton, Path=ActualWidth}" Content="{Binding Path=NextButtonText}" />
</Border>
<Border BorderBrush="Transparent"
BorderThickness="0"
Padding="3,3,8,3">
<Button Width="{Binding ElementName=MaxWidthButton, Path=ActualWidth}" Content="{Binding Path=FinishButtonText}" />
</Border>
<Border BorderBrush="Transparent"
BorderThickness="0"
Padding="8,3,3,3">
<Button Width="{Binding ElementName=MaxWidthButton, Path=ActualWidth}" Content="{Binding Path=CancelButtonText}" />
</Border>
</StackPanel>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.