Автоматическое изменение размера кнопки в ячейке сетки с сохранением соотношения в XAML WPF

#wpf #xaml #button #grid

#wpf #xaml #кнопка #сетка

Вопрос:

Я выравниваю элементы управления (кнопки) моего пользовательского интерфейса с помощью сетки.

Важно, чтобы размер кнопок максимально заполнял ячейку И соблюдалось соотношение, чтобы мои кнопки оставались круглым кругом.

Я выбрал сетку, так как управление размером кнопки с помощью ячейки сетки при изменении размера окна кажется хорошим выбором, чтобы избежать кодирования.

Однако сейчас я борюсь с сохранением соотношения кнопок. Единственный способ, который работал до сих пор, заключался в том, чтобы обернуть мою кнопку в поле просмотра с помощью Stretch=»Uniform». Это нежизнеспособный способ, так как содержимое кнопок тоже будет растянуто / увеличено, что сделает текст слишком большим, см. Скриншот

Я предполагаю, что другим решением может быть использование изображения или svg для круглой кнопки вместо фона с радиусом границы, поскольку они будут преобразованы таким образом, чтобы их соотношение сохранялось автоматически? Однако, если бы я это сделал, мне пришлось бы найти способ добавить текст сверху. Другой возможностью может быть убедиться, что ячейки таблицы всегда имеют одинаковую высоту / ширину? Похоже, это не так-то просто сделать.

Моим предпочтительным решением, если это возможно, было бы продолжать использовать фон с радиусом границы.

 ...
    x:Key="RoundHoverButtonStyle"
    BasedOn="{StaticResource StandardButtonStyle}"
    TargetType="{x:Type Button}">
    <Style.Resources>
        <Style TargetType="Border">
            <Setter Property="CornerRadius" Value="100" />
        </Style>
    </Style.Resources>
...
<Grid Grid.Column="0" ShowGridLines="True">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Viewbox Stretch="Uniform">
        <Button
            x:Name="Button0"
            Grid.Row="1"
            Grid.Column="0"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Background="Black"
            Content="{Binding Path=ButtonConfigModel.ButtonDict[Button0].DisplayName}"
            Foreground="White"
            Style="{StaticResource RoundHoverButtonStyle}"
            Tag="{Binding Path=ButtonConfigModel.ButtonDict[Button0].VirtualKey}"
            Visibility="{Binding Path=ButtonConfigModel.ButtonDict[Button0].IsEnabled, Converter={StaticResource BoolToVis}}" />
    </Viewbox>
...
 

Ответ №1:

Я думаю, что для вас подойдет работа с многозначным преобразователем, который затем связывается с высотой и шириной кнопки. А высота и ширина кнопки будут многократно привязаны к окружению DockPanel . Это звучит сбивающе с толку — и это немного так. Но я думаю, что нижеприведенное внесет ясность. Я уверен, что есть более одного способа сделать это, но это работает для меня:

Во-первых, в вашем .cs файле для вашего окна добавьте этот многозначный преобразователь — я помещаю свой в конец файла.

 [ValueConversion(typeof(double), typeof(double))]
public class HeightWidthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        double width = (double) values[0];
        double height = (double) values[1];

        return height - width <= 0 ? height : width;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }
}
 

Обратите внимание, что этот преобразователь значений упрощен — вы должны добавить некоторые проверки, чтобы убедиться, что предоставлена правильная информация, чтобы предотвратить получение исключения like InvalidCast или какого-либо другого исключения.

Затем в окне.Раздел Ресурсы вам нужно будет добавить ссылку на этот преобразователь значений:

 <local:HeightWidthConverter x:Key="HeightWidthConverter"/>
 

Предполагается, что у вас есть атрибут xmlns с именем local, который ссылается на пространство имен вашего окна. Это будет выглядеть примерно так:

 xmlns:local="clr-namespace:MyApp"
 

наконец, каждая кнопка будет обернута символом a DockPanel , а высота и ширина кнопки будут привязаны к фактической высоте и фактической ширине DockPanel , как это:

 <Grid
        Grid.Column="1"
        Grid.Row="1"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch"
        >

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>


    </Grid.RowDefinitions>

    <DockPanel x:Name="dp11"
                Grid.Column="1"
                Grid.Row="1"    
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
            >
        <Button x:Name="Button11"
                Content="Hello"
                Background="Black"
                Foreground="White"
                FontSize="10"
                Style="{DynamicResource RoundHoverButtonStyle}">

            <Button.Width>
                <MultiBinding Converter="{StaticResource HeightWidthConverter}">
                    <Binding ElementName="dp11" Path="ActualHeight" />
                    <Binding ElementName="dp11" Path="ActualWidth" />
                </MultiBinding>
            </Button.Width>
            <Button.Height>
                <MultiBinding Converter="{StaticResource HeightWidthConverter}">
                    <Binding ElementName="dp11" Path="ActualHeight" />
                    <Binding ElementName="dp11" Path="ActualWidth" />
                </MultiBinding>
            </Button.Height>
        </Button></DockPanel>

    <Grid.Resources>
        <Style x:Key="RoundHoverButtonStyle"
                TargetType="Button"
                >
            <Style.Resources>
                <Style TargetType="Border">
                    <Setter Property="CornerRadius" Value="100" />
                </Style>
            </Style.Resources>

        </Style>
    </Grid.Resources>
</Grid>
 

Хитрость здесь в том, что MultiConverter получает как фактическую ширину, так и фактическую высоту DockPanel . Затем он определяет, какой из них меньше, и возвращает это значение. И, поскольку он выполняет одинаковые вычисления как для высоты, так и для ширины кнопки, кнопка будет иметь одинаковые значения высоты и ширины. Кроме того, поскольку DockPanel изменение размеров соответствует окружающей сетке (при условии, что эта способность реализована), Button она также автоматически изменит размер.

Используя этот метод, каждая кнопка будет иметь одинаковую высоту и ширину (т.е. Быть круглой).

Причина переноса кнопки в a DockPanel заключается в том, что она будет отображаться / изменяться перед кнопкой, и поэтому кнопка будет иметь значения размера для работы (кстати, это очень большое упрощение). Кроме того, я обнаружил DockPanel , что a лучше справляется с заполнением себя в пределах доступного пространства, чем a StackPanel .