WPF: establecer el ancho (y la altura) como un valor de porcentaje

149

Digamos que quiero TextBlockque sea Widthigual a su contenedor principal Width(es decir, estirar de lado a lado) o un porcentaje de su contenedor principal Width, ¿cómo puedo lograr esto XAMLsin especificar valores absolutos?

Quiero hacer esto para que si el contenedor del Contenedor principal se expande más tarde (se ' Widthaumenta), sus' Elementos secundarios también se expandirán automáticamente. (básicamente, como en HTML y CSS)

Andreas Grech
fuente
Echa un vistazo a esta respuesta .
Jesper Fyhr Knudsen el
Use la respuesta de cwap e incluya la tb en una cuadrícula configurando su alineación para estirar.
Shimmy Weitzhandler

Respuestas:

90

La forma de estirarlo al mismo tamaño que el contenedor principal es usar el atributo:

 <Textbox HorizontalAlignment="Stretch" ...

Eso hará que el elemento Textbox se estire horizontalmente y llene todo el espacio primario horizontalmente (en realidad depende del panel principal que esté utilizando, pero debería funcionar en la mayoría de los casos).

Los porcentajes solo se pueden usar con valores de celda de cuadrícula, por lo que otra opción es crear una cuadrícula y colocar su cuadro de texto en una de las celdas con el porcentaje apropiado.

gcores
fuente
221

Puede colocar los cuadros de texto dentro de una cuadrícula para hacer valores porcentuales en las filas o columnas de la cuadrícula y dejar que los cuadros de texto se llenen automáticamente en sus celdas principales (como lo harán de manera predeterminada). Ejemplo:

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

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

Esto hará que # 1 2/5 del ancho y # 2 3/5.

cwap
fuente
77
Ya lo intenté, pero recibo este error: la cadena '2 *' no se puede convertir a Longitud '.
Andreas Grech el
66
En realidad, * (Asterisk) es una pequeña estrella;) etymonline.com/index.php?term=asterisk
Pratik Deoghare
73
Mi mamá dice que soy una estrella
Denys Wessels
77
Esto no funciona, incluso si TextBox está en una cuadrícula. El ancho se puede establecer en Doble, Doble calificado (Un valor doble seguido de px, in, cm o pt) o Auto. Ver msdn.microsoft.com/en-GB/library/…
Darren
2
Sí. En realidad, esta es una respuesta muy pobre, pero en base a todos los votos positivos, supongo que ayudó a alguien (fue hace mucho tiempo), por lo que no la he eliminado.
cwap
58

Por lo general, usaría un control de diseño incorporado apropiado para su escenario (por ejemplo, use una cuadrícula como padre si desea escalar en relación con el padre). Si desea hacerlo con un elemento padre arbitrario, puede crear un ValueConverter, pero probablemente no será tan limpio como quisiera. Sin embargo, si lo necesita absolutamente, podría hacer algo como esto:

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 se puede usar así, para obtener un cuadro de texto secundario del 10% del ancho de su lienzo principal:

<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
fuente
Esto es realmente genial, ¿cómo puedo hacerlo en código (establecer el ancho del cuadro de texto)?
Jeremy
9
Debería considerar agregar CultureInfo.InvariantCulturea la doble conversión porque parameterse considera que stringy en culturas con diferentes decimal separatorno funcionará como se esperaba.
Flat Eric
33

Para cualquiera que reciba un error como: la cadena '2 *' no se puede convertir a Longitud.

<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
fuente
¿Por qué no <RowDefinition Height="auto" />?
Ben
2
"auto" ocupa solo el espacio que necesita el control
Yama
Muchas gracias, esta debería ser la mejor respuesta.
Mafii
Esta es definitivamente la mejor respuesta.
Knut Valen
7

Se puede usar la implementación de IValueConverter. La clase de convertidor que se hereda de IValueConverter toma algunos parámetros como value(porcentaje) y parameter(ancho del padre) y devuelve el valor de ancho deseado. En el archivo XAML, el ancho del componente se establece con el valor deseado:

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
fuente
4

Sé que no es Xaml, pero hice lo mismo con el evento SizeChanged del cuadro 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);
}

El cuadro de texto parece tener un tamaño del 80% de su elemento primario (el margen del lado derecho es del 20%) y se estira cuando es necesario.

Crippeoblade
fuente
4

Yo uso dos métodos para el tamaño relativo. Tengo una clase llamada Relativecon tres propiedades adjuntas To, WidthPercenty HeightPercentque es útil si quiero que un elemento tenga un tamaño relativo de un elemento en cualquier parte del árbol visual y se sienta menos hacky que el enfoque del convertidor, aunque use lo que funciona para usted, que Estás contento con.

El otro enfoque es bastante más astuto. Agregue un lugar ViewBoxdonde desee tamaños relativos dentro, luego dentro de eso, agregue un Gridancho de 100. Luego, si agrega un TextBlockancho de 10 dentro de eso, obviamente es el 10% de 100.

El ViewBoxescalará el Gridacuerdo con cualquier espacio que se le ha dado, así que si es la única cosa en la página, a continuación, el Gridserá escalado a cabo ancho completo y eficaz, suTextBlock se escala al 10% de la página.

Si no establece una altura en el, Gridentonces se reducirá para ajustarse a su contenido, por lo que todo tendrá un tamaño relativamente. Tendrá que asegurarse de que el contenido no sea demasiado alto, es decir, comience a cambiar la relación de aspecto del espacio dado, de lo ViewBoxcontrario, también comenzará a escalar la altura. Probablemente pueda solucionar esto con un Stretchde UniformToFill.

Luke Puplett
fuente