WPF: установка ширины (и высоты) в процентах

Скажите, что я хочу, чтобы TextBlock имел свой Width равный ему родительский контейнер Width (т.е. растягивался из стороны в сторону) или процент от него Parent Container Width, как я могу выполнить это в XAML без указания абсолютных значений?

Я хочу сделать это, чтобы, если контейнер родительского контейнера позже расширится (его "Width увеличено), его" дочерние элементы "также будут автоматически расширены. (в основном, как в HTML и CSS)

Ответ 1

Способ растянуть его до того же размера, что и родительский контейнер, должен использовать атрибут:

 <Textbox HorizontalAlignment="Stretch" ...

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

Проценты могут использоваться только со значениями ячейки сетки, поэтому другой вариант заключается в создании сетки и помещении вашего текстового поля в одну из ячеек с соответствующим процентом.

Ответ 2

Это обновленный ответ на мой предыдущий пост от '09 и содержащий неверную информацию. Следующий пример должен быть лучше:

Вы можете поместить текстовые поля внутри сетки, чтобы делать процентные значения в строках или столбцах сетки, и позволить текстовым полям автоматически заполнять их родительские ячейки (как они будут по умолчанию). Пример:

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

    <TextBox Grid.Column="0" />
    <TextBox Grid.Column="1" />
</Grid>

Это сделает № 1 2/5 ширины и # 2 3/5.

Исходное сообщение с неправильной/неполной информацией

Не думайте, что вы можете сделать%, но вы можете сделать *:)

Пример:

<TextBox width="2*"/>
<TextBox width="3*"/>

Это сделает № 1 2/5 ширины и # 2 3/5.

Ответ 3

Как правило, вы должны использовать встроенный макет, соответствующий вашему сценарию (например, использовать сетку в качестве родителя, если вы хотите масштабирование относительно родителя). Если вы хотите сделать это с помощью произвольного родительского элемента, вы можете создать ValueConverter, но это, вероятно, будет не так чисто, как вам хотелось бы. Однако, если вы в ней абсолютно нуждаетесь, вы можете сделать что-то вроде этого:

public class PercentageConverter : IValueConverter
{
    public object Convert(object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        return System.Convert.ToDouble(value) * 
               System.Convert.ToDouble(parameter);
    }

    public object ConvertBack(object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Что можно использовать так, чтобы получить дочернее текстовое поле на 10% от ширины его родительского холста:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:PercentageConverter x:Key="PercentageConverter"/>
    </Window.Resources>
    <Canvas x:Name="canvas">
        <TextBlock Text="Hello"
                   Background="Red" 
                   Width="{Binding 
                       Converter={StaticResource PercentageConverter}, 
                       ElementName=canvas, 
                       Path=ActualWidth, 
                       ConverterParameter=0.1}"/>
    </Canvas>
</Window>

Ответ 4

Для любого, кто получает ошибку, например: '2 *' строка не может быть преобразована в длину.

<Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" /><!--This will make any control in this column of grid take 2/5 of total width-->
        <ColumnDefinition Width="3*" /><!--This will make any control in this column of grid take 3/5 of total width-->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition MinHeight="30" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Grid.Row="0">Your text block a:</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="0">Your text block b:</TextBlock>
</Grid>

Ответ 5

Я использую два метода для относительного размера. У меня есть класс под названием Relative с тремя прикрепленными свойствами To, WidthPercent и HeightPercent, который полезен, если я хочу, чтобы элемент был относительным размером элемента в любом месте визуального дерева и чувствовал себя менее взломанным, чем конвертер подход - хотя использовать то, что работает для вас, что вы довольны.

Другой подход более хитер. Добавьте ViewBox, где вы хотите относительные размеры внутри, а затем внутри, добавьте Grid шириной 100. Затем, если вы добавите TextBlock с шириной 10 внутри, это, очевидно, 10% от 100.

ViewBox будет масштабировать Grid в соответствии с любым пространством, которое оно было задано, поэтому, если это единственное, что отображается на странице, то Grid будет масштабироваться по всей ширине и эффективно, ваш TextBlock масштабируется до 10% страницы.

Если вы не установите высоту на Grid, тогда она будет уменьшаться, чтобы соответствовать ее контенту, поэтому все будет относительно небольшим. Вы должны будете убедиться, что контент не становится слишком высоким, т.е. Начинает изменять соотношение сторон пространства, указанного в ViewBox, иначе он начнет масштабировать высоту. Вероятно, вы можете обойти это с помощью Stretch UniformToFill.

Ответ 6

Я знаю, что это не Xaml, но я сделал то же самое с событием SizeChanged в текстовом поле:

private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
   TextBlock textBlock = sender as TextBlock;
   FrameworkElement element = textBlock.Parent as FrameworkElement;
   textBlock.Margin = new Thickness(0, 0, (element.ActualWidth / 100) * 20, 0);
}

Текстовое поле, по-видимому, составляет 80% от его родительского (нужный правый край составляет 20%) и растягивается при необходимости.

Ответ 7

ConverterClass:

public class SizePercentageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (parameter == null)
            return 0.7 * value.ToDouble();

        string[] split = parameter.ToString().Split('.');
        double parameterDouble = split[0].ToDouble() + split[1].ToDouble() / (Math.Pow(10, split[1].Length));
        return value.ToDouble() * parameterDouble;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Don't need to implement this
        return null;
    }
}

XAML:

<UserControl.Resources>
    <m:SizePercentageConverter x:Key="PercentageConverter" />
</UserControl.Resources>

<ScrollViewer VerticalScrollBarVisibility="Auto"
          HorizontalScrollBarVisibility="Disabled"
          Width="{Binding Converter={StaticResource PercentageConverter}, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Border}},Path=ActualWidth}"
          Height="{Binding Converter={StaticResource PercentageConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Border}},Path=ActualHeight}">
....
</ScrollViewer>