簡體   English   中英

WPF:確保按鈕具有相同的寬度

[英]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中完成,沒有任何代碼。 另一件事,可以在運行時更改按鈕內的文本。

任何想法如何做到這一點?

編輯似乎很多人不理解我需要一個具有相同寬度的按鈕,而不是一個具有相同寬度的按鈕和頁邊距。

您所有的解決方案都提供了類似的內容:您可以清楚地看到按鈕的大小不一樣(我將“ 8”邊距值增加了,以更好地顯示問題)。 在此處輸入圖片說明

這是我想要實現的(我欺騙了一些固定值): 在此處輸入圖片說明

這是一個繼承標准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的MarginBorder沒有厚度,沒有電刷和Padding具有所需保證金。

然后,如果采用以下解決方案,則必須事先知道哪個Button具有最大寬度。 因為我們需要將此ButtonActualWidth復制到所有其他ButtonWidth

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM