WPF: Festlegen der Breite (und Höhe) als Prozentwert

149

Angenommen, ich möchte TextBlock, dass ein WidthWert dem übergeordneten Container Width(dh von Seite zu Seite) oder einem Prozentsatz des übergeordneten Containers entspricht Width. Wie kann ich dies erreichen, XAMLohne absolute Werte anzugeben?

Ich möchte dies tun, damit, wenn der übergeordnete Container-Container später erweitert wird (sein " Widtherhöht"), seine "untergeordneten Elemente" ebenfalls automatisch erweitert werden. (im Grunde wie in HTML und CSS)

Andreas Grech
quelle
Schauen Sie sich diese Antwort an .
Jesper Fyhr Knudsen
Verwenden Sie die Antwort von cwap und fügen Sie das tb in eine Rastereinstellung ein, deren Ausrichtung zum Strecken ausgerichtet ist.
Shimmy Weitzhandler

Antworten:

89

Um es auf die gleiche Größe wie den übergeordneten Container zu dehnen, verwenden Sie das folgende Attribut:

 <Textbox HorizontalAlignment="Stretch" ...

Dadurch wird das Textbox-Element horizontal gestreckt und der gesamte übergeordnete Bereich horizontal ausgefüllt (dies hängt tatsächlich vom übergeordneten Bedienfeld ab, das Sie verwenden, sollte jedoch in den meisten Fällen funktionieren).

Prozentsätze können nur mit Rasterzellenwerten verwendet werden. Eine weitere Option besteht darin, ein Raster zu erstellen und Ihr Textfeld mit dem entsprechenden Prozentsatz in eine der Zellen einzufügen.

gcores
quelle
220

Sie können die Textfelder in ein Raster einfügen, um Prozentwerte für die Zeilen oder Spalten des Rasters zu erstellen, und die Textfelder automatisch in ihre übergeordneten Zellen füllen lassen (wie dies standardmäßig der Fall ist). Beispiel:

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

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

Dies ergibt # 1 2/5 der Breite und # 2 3/5.

cwap
quelle
7
Ich habe das bereits versucht, aber es wird folgende Fehlermeldung angezeigt: '2 *' Zeichenfolge kann nicht in Länge konvertiert werden. '
Andreas Grech
6
Eigentlich ist * (Sternchen) ein kleiner Stern;) etymonline.com/index.php?term=asterisk
Pratik Deoghare
73
Meine Mutter sagt, ich bin ein Star
Denys Wessels
7
Dies funktioniert nicht, selbst wenn sich die TextBox in einem Raster befindet. Die Breite kann auf Double, Qualified Double (ein Doppelwert gefolgt von px, in, cm oder pt) oder Auto eingestellt werden. Siehe msdn.microsoft.com/en-GB/library/…
Darren
2
Ja. Dies ist eigentlich eine sehr schlechte Antwort, aber aufgrund all der positiven Stimmen hat sie vermutlich jemandem geholfen (war vor langer Zeit), weshalb ich sie nicht gelöscht habe.
cwap
57

In der Regel verwenden Sie ein für Ihr Szenario geeignetes integriertes Layout-Steuerelement (z. B. ein Raster als übergeordnetes Element, wenn Sie eine Skalierung relativ zum übergeordneten Element wünschen). Wenn Sie dies mit einem beliebigen übergeordneten Element tun möchten, können Sie einen ValueConverter erstellen, der dies jedoch wahrscheinlich nicht ganz so sauber macht, wie Sie möchten. Wenn Sie es jedoch unbedingt benötigen, können Sie Folgendes tun:

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

Was so verwendet werden kann, um ein untergeordnetes Textfeld 10% der Breite seiner übergeordneten Zeichenfläche zu erhalten:

<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
quelle
Das ist wirklich cool, wie kann ich das im Code machen (die Breite des Textfelds einstellen)?
Jeremy
9
Sie sollten in Betracht ziehen, CultureInfo.InvariantCulturezur doppelten Konvertierung hinzuzufügen , da dies parameterals stringund in Kulturen mit unterschiedlichen Konvertierungen decimal separatornicht wie erwartet funktioniert.
Wohnung Eric
33

Für alle, die eine Fehlermeldung erhalten wie: '2 *' Zeichenfolge kann nicht in Länge konvertiert werden.

<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
quelle
Warum nicht <RowDefinition Height="auto" />?
Ben
2
"Auto" nimmt nur so viel Platz ein, wie die Steuerung benötigt
Yama
Vielen Dank, dies sollte die beste Antwort sein.
Mafii
Dies ist definitiv die beste Antwort.
Knut Valen
7

Die IValueConverter-Implementierung kann verwendet werden. Konverterklassen, die von IValueConverter vererbt werden, verwenden einige Parameter wie value(Prozent) und parameter(übergeordnete Breite) und geben den gewünschten Breitenwert zurück. In der XAML-Datei wird die Breite der Komponente auf den gewünschten Wert festgelegt:

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 Katamak
quelle
4

Ich weiß, dass es nicht Xaml ist, aber ich habe dasselbe mit dem SizeChanged-Ereignis des Textfelds gemacht:

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

Das Textfeld scheint 80% der Größe des übergeordneten Felds zu haben (der rechte Rand beträgt 20%) und wird bei Bedarf gedehnt.

Crippeoblade
quelle
4

Ich benutze zwei Methoden für die relative Dimensionierung. Ich habe eine Klasse namens Relativemit drei angefügten Eigenschaften To, WidthPercentund HeightPercentdas ist nützlich , wenn ich ein Element soll eine relative Größe eines Element überall in der visuellen Struktur sein und fühle mich weniger hacky als die Konverter Ansatz - obwohl die Verwendung , was für Sie, dass Sie bin glücklich mit.

Der andere Ansatz ist eher gerissen. Fügen Sie eine Stelle hinzu, ViewBoxan der Sie relative Größen möchten, und fügen Sie dann eine Gridbei Breite 100 hinzu. Wenn Sie dann eine TextBlockmit einer Breite von 10 hinzufügen , sind dies offensichtlich 10% von 100.

Das ViewBoxwird Gridentsprechend dem Platz skaliert, den es erhalten hat. Wenn es also das einzige auf der Seite ist, Gridwird das in voller Breite skaliert und effektiv wird TextBlockes auf 10% der Seite skaliert.

Wenn Sie keine Höhe für das festlegen Grid, wird es verkleinert, um seinem Inhalt zu entsprechen, sodass alles relativ groß ist. Sie müssen sicherstellen, dass der Inhalt nicht zu groß wird, dh das Seitenverhältnis des zugewiesenen Speicherplatzes ändert, ViewBoxum die Höhe zu skalieren. Sie können dies wahrscheinlich mit einem Stretchvon umgehen UniformToFill.

Luke Puplett
quelle