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

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

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

7 ответов


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

 <Textbox HorizontalAlignment="Stretch" ...

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

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


это обновленный ответ на мой предыдущий пост с ' 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.


обычно вы используете встроенный элемент управления макетом, соответствующий вашему сценарию (например, используйте сетку в качестве родителя, если вы хотите масштабировать относительно родителя). Если вы хотите сделать это с произвольным родительским элементом, вы можете создать 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>

для всех, кто получает ошибку, например:'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>

Я знаю, что это не 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%) и растягивается при необходимости.


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

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

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

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


может использоваться реализация IValueConverter. Класс конвертера, который принимает наследование от IValueConverter, принимает некоторые параметры, такие как value (проценты) и parameter (родительская ширина) и возвращает желаемое значение ширины. В XAML-файле ширина компонента устанавливается с желаемым значением:

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>