WPF: definindo a largura (e altura) como um valor percentual

149

Digamos que eu queira TextBlockque seja Widthigual ao contêiner pai Width(ou seja, estique de um lado para o outro) ou uma porcentagem do contêiner pai Width, como posso fazer isso XAMLsem especificar valores absolutos?

Eu quero fazer isso para que, se o contêiner pai Container for expandido posteriormente (seu ' Widthaumentado), seus' elementos filho também serão expandidos automaticamente. (basicamente, como em HTML e CSS)

Andreas Grech
fonte
Dê uma olhada nesta resposta .
Jesper Fyhr Knudsen 04/04/09
Use a resposta do cwap e inclua o tb em uma configuração de grade que é alinhada para esticar.
Shimmy Weitzhandler

Respostas:

90

A maneira de esticá-lo para o mesmo tamanho que o contêiner pai é usar o atributo:

 <Textbox HorizontalAlignment="Stretch" ...

Isso fará o elemento Textbox esticar horizontalmente e preencher todo o espaço pai horizontalmente (na verdade, depende do painel pai que você está usando, mas deve funcionar na maioria dos casos).

As porcentagens só podem ser usadas com os valores das células da grade; portanto, outra opção é criar uma grade e colocar sua caixa de texto em uma das células com a porcentagem apropriada.

gcores
fonte
221

Você pode colocar as caixas de texto dentro de uma grade para fazer valores percentuais nas linhas ou colunas da grade e deixar que as caixas de texto sejam preenchidas automaticamente nas células-pai (como serão por padrão). Exemplo:

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

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

Isso tornará # 1 2/5 da largura e # 2 3/5.

cwap
fonte
7
Eu já tentei isso, mas estou recebendo este erro: '2 *' a string não pode ser convertida em Comprimento. '
Andreas Grech
6
Na verdade, * (Asterisk) é uma pequena estrela;) etymonline.com/index.php?term=asterisk
Pratik Deoghare
73
Minha mãe diz que sou estrela
Denys Wessels
7
Isso não funciona, mesmo se o TextBox estiver em uma grade. A largura pode ser definida como Duplo, Duplo qualificado (Um valor duplo seguido de px, pol, cm ou pt) ou Automático. Consulte msdn.microsoft.com/pt-BR/library/…
Darren,
2
Sim. Na verdade, essa é uma resposta muito ruim, mas com base em todos os votos positivos, acho que ajudou alguém (foi há muito tempo), e é por isso que não a excluí.
Cwap
58

Normalmente, você usaria um controle de layout interno apropriado para o seu cenário (por exemplo, use uma grade como pai, se desejar dimensionar em relação ao pai). Se você quiser fazer isso com um elemento pai arbitrário, poderá criar um ValueConverter, mas provavelmente não será tão limpo quanto você gostaria. No entanto, se você absolutamente precisar, poderá fazer algo assim:

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();
    }
}

Que pode ser usado assim, para obter uma caixa de texto filho com 10% da largura da tela pai:

<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>
kvb
fonte
Isso é muito legal, como posso fazer isso no código (defina a largura da caixa de texto)?
Jeremy
9
Você deve considerar CultureInfo.InvariantCulturea possibilidade de adicionar à conversão dupla, pois a parameteré considerada como stringe em culturas com diferentes decimal separatorela não funcionará conforme o esperado.
Flat Eric
33

Para quem está recebendo um erro como: '2 *' a string não pode ser convertida em Length.

<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>
Zain Ali
fonte
Por que não <RowDefinition Height="auto" />?
Ben
2
"auto" leva apenas tanto espaço quanto as necessidades de controle
Yama
Muito obrigado, esta deve ser a melhor resposta.
Mafii 28/06
Esta é definitivamente a melhor resposta.
precisa
7

A implementação IValueConverter pode ser usada. A classe de conversor que recebe herança de IValueConverter usa alguns parâmetros como value(porcentagem) e parameter(largura dos pais) e retorna o valor da largura desejada. No arquivo XAML, a largura do componente é definida com a desejada com o valor:

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>
Adem Catamak
fonte
4

Eu sei que não é Xaml, mas fiz o mesmo com o evento SizeChanged da caixa de texto:

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);
}

A caixa de texto parece ter 80% do tamanho de sua matriz (a margem do lado direito é de 20%) e se estende quando necessário.

Crippeoblade
fonte
4

Eu uso dois métodos para dimensionamento relativo. Eu tenho uma classe chamada Relativecom três propriedades anexadas To, WidthPercenteHeightPercent que é útil se eu quiser que um elemento seja do tamanho relativo de um elemento em qualquer lugar da árvore visual e parecer menos invasivo que a abordagem do conversor - embora use o que funciona melhor para você estou feliz com.

A outra abordagem é bastante mais esperta. Adicione um ViewBoxlocal em que deseja tamanhos relativos e, dentro dele, adicione um Gridna largura 100. Em seguida, se você adicionar umTextBlock com largura 10, é obviamente 10% de 100.

Ele ViewBoxserá dimensionado de Gridacordo com o espaço fornecido, portanto, se for a única coisa na página, Gridserá dimensionado para toda a largura e, efetivamente, você TextBlockserá dimensionado para 10% da página.

Se você não definir uma altura no Grid , ela diminuirá para se ajustar ao seu conteúdo, de modo que tudo será relativamente pequeno. Você terá que garantir que o conteúdo não fique muito alto, ou seja, comece a alterar a proporção do espaço fornecido, caso ViewBoxcontrário, começará a dimensionar a altura também. Provavelmente, você pode contornar isso com um Stretchde UniformToFill.

Luke Puplett
fonte