web-dev-qa-db-fra.com

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

Dites que je veux qu'une TextBlock ait sa Width égale à celle de son conteneur parent Width (c'est-à-dire qu'elle s'étire d'un côté à l'autre) ou à un pourcentage de son conteneur parent Width, comment puis-je accomplir cela dans XAML sans spécifier de valeurs absolues?

Je souhaite effectuer cette opération de sorte que, si le conteneur de conteneur parent est ultérieurement développé (son nombre _ Width augmenté), ses 'éléments enfants sont également développés automatiquement. (fondamentalement, comme en HTML et CSS)

143
Andreas Grech

Pour l'étendre à la même taille que le conteneur parent, utilisez l'attribut suivant:

 <Textbox HorizontalAlignment="Stretch" ...

Cela fera en sorte que l'élément Textbox s'étire horizontalement et remplisse tout l'espace parent horizontalement (en réalité, cela dépend du panneau parent que vous utilisez mais devrait fonctionner dans la plupart des cas).

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

84
gcores

Vous pouvez placer les zones de texte dans une grille pour définir des pourcentages sur les lignes ou les colonnes de la grille et laisser les zones de texte se remplir automatiquement dans leurs cellules parentes (comme elles le seront 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.

203
cwap

En règle générale, vous utiliseriez un contrôle de présentation intégré approprié à votre scénario (par exemple, utilisez une grille en tant que parent si vous souhaitez une mise à l'échelle relative au parent). Si vous voulez le faire avec un élément parent arbitraire, vous pouvez créer un ValueConverter, 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 un champ de texte enfant 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>
54
kvb

Pour tous ceux qui obtiennent une erreur du type: 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>
30
Zain Ali

La mise en œuvre IValueConverter peut être utilisée. La classe de convertisseur qui hérite d'IValueConverter prend des paramètres tels que 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>
5
Adem Catamak

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 une taille de 80% de son parent (la marge du côté droit est de 20%) et s’étire au besoin.

4
Crippeoblade

J'utilise deux méthodes pour le dimensionnement relatif. J'ai une classe appelée Relative avec trois propriétés attachées To, WidthPercent et HeightPercent qui est utile si je veux qu'un élément soit la taille relative d'un élément n'importe où dans le arbre visuel et se sent moins hacky que l'approche de convertisseur - bien utiliser ce qui fonctionne pour vous, que vous êtes heureux avec.

L'autre approche est un peu plus rusé. Ajoutez un ViewBox là où vous voulez des tailles relatives, puis ajoutez un Grid de largeur 100. Si vous ajoutez un TextBlock de largeur 10, il est évidemment de 10%. de 100.

La ViewBox redimensionnera la Grid en fonction de l'espace qui lui a été attribué. Si c'est le seul élément de la page, alors la Grid sera mise à l'échelle sur toute la largeur et efficacement, votre TextBlock est mis à l'échelle à 10% de la page.

Si vous ne définissez pas de hauteur sur la Grid, elle sera réduite pour correspondre à son contenu, de sorte qu'elle aura toutes une taille relative. Vous devrez vous assurer que le contenu ne devient pas trop haut, c'est-à-dire qu'il commence à modifier le rapport de format de l'espace donné au ViewBox, sinon il commencera également à redimensionner la hauteur. Vous pouvez probablement contourner ce problème avec une Stretch sur UniformToFill.

4
Luke Puplett