WPF: установка ширины (и высоты) в процентах - PullRequest
139 голосов
/ 04 апреля 2009

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

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

Ответы [ 7 ]

200 голосов
/ 04 апреля 2009

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

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

83 голосов
/ 04 апреля 2009

Чтобы растянуть его до размера родительского контейнера, используйте атрибут:

 <Textbox HorizontalAlignment="Stretch" ...

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

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

54 голосов
/ 04 апреля 2009

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

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

Может использоваться реализация 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>
4 голосов
/ 30 июля 2013

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

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

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

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

4 голосов
/ 05 апреля 2009

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

...