WPF: définition de la largeur (et de la hauteur) en tant que valeur de pourcentage
Disons que je veux qu'un TextBlock
ait son Width
égal à son conteneur Parent Width
(c'est-à-dire, étirer 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 veux faire ceci de sorte que si le conteneur de conteneur Parent est plus tard développé (son 'Width
augmenté), ses ' éléments enfants seront également développés automatiquement. (fondamentalement, comme en HTML et CSS)
7 réponses
Le chemin de l'étirer à la même taille que le conteneur parent est d'utiliser l'attribut:
<Textbox HorizontalAlignment="Stretch" ...
Cela fera que L'élément Textbox s'étire horizontalement et remplira 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 des cellules de la grille, une autre option consiste à créer une grille et à placer votre zone de texte dans l'une des cellules avec le pourcentage approprié.
Ceci est une réponse mise à jour à mon post précédent de '09 et qui contenait des informations incorrectes. L'exemple suivant devrait s'avérer meilleur:
Vous pouvez placer les zones de texte dans une grille pour faire des valeurs de pourcentage sur les lignes ou les colonnes de la grille et laisser les zones de texte remplir automatiquement 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 #1 2/5 de la largeur, et #2 3/5.
Message Original avec incorrect / Non complet informations
Ne pensez pas que vous pouvez faire%, mais vous pouvez faire*:)
Exemple:
<TextBox width="2*"/>
<TextBox width="3*"/>
Cela fera #1 2/5 de la largeur, et #2 3/5.
Généralement, vous utiliserez un contrôle de mise en page intégré approprié à votre scénario (par exemple, utilisez une grille en tant que parent si vous voulez mettre à l'échelle par rapport 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 souhaitez. 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();
}
}
Qui peut être utilisé comme ceci, pour obtenir une zone de texte enfant 10% de la largeur de son parent toile:
<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>
Pour quiconque obtient une erreur comme : '2*' la chaîne 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>
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 de droite est de 20%) et s'étire en cas de besoin.
J'utilise deux méthodes pour le dimensionnement relatif. J'ai une classe appelée Relative
avec trois propriétés attachéesTo
, WidthPercent
et HeightPercent
ce qui est utile si je veux qu'un élément soit une taille relative d'un élément n'importe où dans l'arbre visuel et se sent moins hacky que l'approche du convertisseur - bien qu'utiliser ce qui fonctionne pour vous, que vous êtes satisfait.
L'autre approche est un peu plus rusée. Ajoutez un ViewBox
où vous voulez des tailles relatives à l'intérieur, puis à l'intérieur, ajoutez un Grid
à la largeur 100. Alors si vous ajoutez un TextBlock
avec une largeur 10 à l'intérieur, c'est évidemment 10% de 100.
Le ViewBox
va mettre à l'échelle le Grid
en fonction de l'espace qui lui a été donné, donc si c'est la seule chose sur la page, alors le Grid
sera mis à l'échelle pleine largeur et effectivement, votre TextBlock
est mis à l'échelle à 10% de la page.
Si vous ne définissez pas de hauteur sur le Grid
, il 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 grand, c'est-à-dire commence à changer le rapport d'aspect de l'espace donné au ViewBox
sinon, il commencera également à mettre à l'échelle la hauteur. Vous pouvez probablement contourner cela avec un Stretch
de UniformToFill
.
L'implémentation IValueConverter peut être utilisée. La classe Converter qui prend l'héritage de IValueConverter prend certains paramètres comme value
(Pourcentage) et parameter
(largeur du parent) et renvoie la valeur de largeur désiré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>