WPF: définition de la largeur (et de la hauteur) en tant que valeur de pourcentage

150

Disons que je veux que un TextBlocksoit Widthégal à son conteneur parent Width(c'est-à-dire, étiré d'un côté à l'autre) ou à un pourcentage de son conteneur parent Width, comment puis-je accomplir cela XAMLsans spécifier de valeurs absolues?

Je veux faire cela pour que si le conteneur du conteneur parent est ultérieurement développé (son ' Widthaugmenté), ses' éléments enfants seront également développés automatiquement. (en gros, comme en HTML et CSS)

Andreas Grech
la source
Jetez un œil à cette réponse .
Jesper Fyhr Knudsen
Utilisez la réponse de cwap et incluez le tb dans une grille en définissant son alignement à étirer.
Shimmy Weitzhandler le

Réponses:

91

La façon de l'étirer à la même taille que le conteneur parent consiste à utiliser l'attribut:

 <Textbox HorizontalAlignment="Stretch" ...

Cela rendra l'élément Textbox s'étirer horizontalement et remplir tout l'espace parent horizontalement (en fait, cela dépend du panneau parent que vous utilisez mais devrait fonctionner dans la plupart des cas).

Les pourcentages ne peuvent être utilisés qu'avec les valeurs de cellule de la grille, une autre option consiste donc à créer une grille et à placer votre zone de texte dans l'une des cellules avec le pourcentage approprié.

gcores
la source
222

Vous pouvez placer les zones de texte dans une grille pour faire des valeurs de pourcentage sur les lignes ou colonnes de la grille et laisser les zones de texte se remplir automatiquement vers leurs cellules parentes (comme elles le feront par défaut). Exemple:

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

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

Cela fera n ° 1 2/5 de la largeur et n ° 2 3/5.

cwap
la source
7
J'ai déjà essayé cela, mais j'obtiens cette erreur: la chaîne '2 *' ne peut pas être convertie en longueur. '
Andreas Grech
6
En fait, * (Asterisk) est une petite étoile;) etymonline.com/index.php?term=asterisk
Pratik Deoghare
73
Ma mère dit que je suis une star
Denys Wessels
7
Cela ne fonctionne pas, même si la zone de texte est dans une grille. La largeur peut être définie sur Double, Double qualifié (une valeur double suivie de px, in, cm ou pt) ou Auto. Voir msdn.microsoft.com/en-GB/library/…
Darren
2
Oui. C'est en fait une très mauvaise réponse, mais sur la base de tous les votes positifs, je suppose que cela a aidé quelqu'un (c'était il y a longtemps), c'est pourquoi je ne l'ai pas supprimé.
cwap
59

En règle générale, vous utilisez un contrôle de mise en page intégré adapté à votre scénario (par exemple, utilisez une grille en tant que parent si vous souhaitez une mise à l'échelle par rapport au parent). Si vous voulez le faire avec un élément parent arbitraire, vous pouvez créer un ValueConverter pour le faire, mais il ne sera probablement pas aussi propre que vous le souhaiteriez. Cependant, si vous en avez absolument besoin, vous pouvez faire quelque chose comme ceci:

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

Ce qui peut être utilisé comme ceci, pour obtenir une zone de texte enfant de 10% de la largeur de son canevas parent:

<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
la source
C'est vraiment cool, comment puis-je le faire dans le code (définir la largeur de la zone de texte)?
Jeremy
9
Vous devriez envisager d'ajouter CultureInfo.InvariantCultureà la double conversion car le parameterest considéré comme stringet dans les cultures avec différentes, decimal separatoril ne fonctionnera pas comme prévu.
Flat Eric
33

Pour toute personne qui obtient une erreur telle que: la chaîne '2 *' ne peut pas être convertie en longueur.

<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
la source
Pourquoi pas <RowDefinition Height="auto" />?
Ben
2
"auto" prend autant de place que le contrôle a besoin
Yama
Merci beaucoup, cela devrait être la meilleure réponse.
Mafii
C'est certainement la meilleure réponse.
Knut Valen
7

L'implémentation IValueConverter peut être utilisée. La classe de convertisseur qui hérite de IValueConverter prend certains paramètres comme value(pourcentage) et parameter(largeur du parent) et renvoie la valeur de largeur souhaitée. Dans le fichier XAML, la largeur du composant est définie avec celle souhaitée avec la valeur:

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
la source
4

Je sais que ce n'est pas Xaml mais j'ai fait la même chose avec l'événement SizeChanged de la zone de texte:

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

La zone de texte semble avoir 80% de la taille de son parent (bien la marge du côté droit est de 20%) et s'étire si nécessaire.

Crippéoblade
la source
4

J'utilise deux méthodes pour le dimensionnement relatif. J'ai une classe appelée Relativeavec trois propriétés attachées To, WidthPercentet HeightPercentqui est utile si je veux qu'un élément soit une taille relative d'un élément n'importe où dans l'arborescence visuelle et se sent moins piraté que l'approche du convertisseur - bien que vous utilisez ce qui fonctionne pour vous, que vous suis content.

L'autre approche est un peu plus rusée. Ajoutez un ViewBoxoù vous voulez des tailles relatives à l'intérieur, puis à l'intérieur, ajoutez un Gridà une largeur de 100. Ensuite, si vous ajoutez un TextBlockavec une largeur de 10 à l'intérieur, c'est évidemment 10% de 100.

Le ViewBoxsera mis à l'échelle en Gridfonction de l'espace qui lui a été donné, donc si c'est la seule chose sur la page, alors le Gridsera mis à l'échelle sur toute la largeur et effectivement, votre TextBlocksera mis à l'échelle à 10% de la page.

Si vous ne définissez pas de hauteur sur le, Gridil se rétrécira pour s'adapter à son contenu, donc tout sera relativement dimensionné. Vous devrez vous assurer que le contenu ne devient pas trop haut, c'est-à-dire qu'il commence à changer le rapport hauteur / largeur de l'espace donné à l' ViewBoxautre, il commencera également à redimensionner la hauteur. Vous pouvez probablement travailler autour de cela avec un Stretchde UniformToFill.

Luke Puplett
la source