WPF: Ustawianie szerokości (i wysokości) jako wartości procentowej

149

Powiedzmy, że chcę, TextBlockaby element był Widthrówny swojemu kontenerowi nadrzędnemu Width(tj. Rozciągał się z boku na bok) lub procentem jego kontenera nadrzędnego Width, jak mogę to osiągnąć XAMLbez podawania wartości bezwzględnych?

Chcę to zrobić, aby jeśli kontener Kontenera nadrzędnego był później rozwinięty (został Widthzwiększony), jego elementy podrzędne również zostały rozszerzone automatycznie. (w zasadzie jak w HTML i CSS)

Andreas Grech
źródło
Spójrz na tę odpowiedź .
Jesper Fyhr Knudsen
Użyj odpowiedzi cwap i dołącz tb do siatki, ustawiając jej wyrównanie na rozciąganie.
Shimmy Weitzhandler

Odpowiedzi:

90

Sposobem na rozciągnięcie go do tego samego rozmiaru co kontener nadrzędny jest użycie atrybutu:

 <Textbox HorizontalAlignment="Stretch" ...

Spowoduje to rozciągnięcie elementu Textbox w poziomie i wypełnienie całej przestrzeni nadrzędnej w poziomie (w rzeczywistości zależy to od używanego panelu nadrzędnego, ale powinno działać w większości przypadków).

Procentów można używać tylko z wartościami komórek siatki, więc inną opcją jest utworzenie siatki i umieszczenie pola tekstowego w jednej z komórek z odpowiednią wartością procentową.

gcores
źródło
221

Możesz umieścić pola tekstowe wewnątrz siatki, aby wykonać wartości procentowe w wierszach lub kolumnach siatki i pozwolić, aby pola tekstowe wypełniły się automatycznie w swoich komórkach nadrzędnych (tak jak domyślnie). Przykład:

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

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

To da # 1 2/5 szerokości, a # 2 3/5.

cwap
źródło
7
Próbowałem już tego, ale pojawia się ten błąd: Nie można przekonwertować ciągu „2 *” na długość ”.
Andreas Grech
6
Właściwie * (gwiazdka) to mała gwiazdka;) etymonline.com/index.php?term=asterisk
Pratik Deoghare
73
Moja mama mówi, że jestem gwiazdą
Denys Wessels
7
To nie działa, nawet jeśli TextBox znajduje się w siatce. Szerokość można ustawić na Double, Qualified Double (wartość podwójna, po której następuje px, in, cm lub pt) lub Auto. Zobacz msdn.microsoft.com/en-GB/library/…
Darren
2
Tak… To właściwie bardzo kiepska odpowiedź, ale biorąc pod uwagę wszystkie upvoty, przypuszczam, że komuś pomogła (dawno temu), dlatego jej nie usunąłem.
cwap
58

Zwykle użyjesz wbudowanej kontrolki układu odpowiedniej dla twojego scenariusza (np. Użyj siatki jako elementu nadrzędnego, jeśli chcesz skalować względem elementu nadrzędnego). Jeśli chcesz to zrobić z dowolnym elementem nadrzędnym, możesz utworzyć ValueConverter, ale prawdopodobnie nie będzie tak czysty, jak byś chciał. Jeśli jednak absolutnie tego potrzebujesz, możesz zrobić coś takiego:

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

Którego można użyć w ten sposób, aby uzyskać podrzędne pole tekstowe 10% szerokości jego nadrzędnego płótna:

<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
źródło
To jest naprawdę fajne, jak mogę to zrobić w kodzie (ustawić szerokość pola tekstowego)?
Jeremy
9
Powinieneś rozważyć dodanie CultureInfo.InvariantCulturedo podwójnej konwersji, ponieważ parameterjest traktowany jako, stringaw kulturach z różnymi decimal separatornie będzie działać zgodnie z oczekiwaniami.
Flat Eric
33

Dla każdego, kto otrzymuje błąd, taki jak: ciąg „2 *” nie może zostać przekonwertowany na długość.

<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
źródło
Dlaczego nie <RowDefinition Height="auto" />?
Ben
2
„auto” zajmuje tylko tyle miejsca, ile potrzebuje sterowanie
Yama
Dziękuję bardzo, to powinna być najlepsza odpowiedź.
Mafii
To zdecydowanie najlepsza odpowiedź.
Knut Valen
7

Można zastosować implementację IValueConverter. Klasa Converter, która dziedziczy z IValueConverter, pobiera niektóre parametry, takie jak value(procent) i parameter(szerokość rodzica) i zwraca żądaną wartość szerokości. W pliku XAML szerokość składnika jest ustawiana na żądaną z wartością:

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
źródło
4

Wiem, że to nie Xaml, ale zrobiłem to samo ze zdarzeniem SizeChanged w polu tekstowym:

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

Pole tekstowe wydaje się mieć 80% rozmiaru swojego rodzica (prawy margines to 20%) i rozciąga się w razie potrzeby.

Crippeoblade
źródło
4

Używam dwóch metod określania rozmiaru względnego. Mam klasy o nazwie Relativez trzech dołączonych właściwości To, WidthPercenta HeightPercentco jest przydatne, jeśli chcę elementem być względna wielkość statku nigdzie elementu w drzewie wizualne i czuje się mniej hacky niż podejście kalkulator - chociaż stosowanie co działa dla ciebie, że ciebie jestem zadowolony z.

Drugie podejście jest bardziej przebiegłe. Dodaj ViewBoxgdzie chcesz mieć względne rozmiary wewnątrz, a następnie w środku dodaj a Grido szerokości 100. Następnie, jeśli dodasz a TextBlocko szerokości 10 w środku, będzie to oczywiście 10% ze 100.

ViewBoxBędzie skalować Gridw zależności od miejsca, co zostało podane, więc jeśli jego jedyną rzeczą, na stronie, a następnie Gridzostanie przeskalowany na pełną szerokość i skutecznie, twój TextBlockjest skalowany do 10% strony.

Jeśli nie ustawisz wysokości na Grid, skurczy się, aby dopasować się do jego zawartości, więc wszystko będzie miało stosunkowo duże rozmiary. Będziesz musiał upewnić się, że treść nie stanie się zbyt wysoka, tj. Zacznie zmieniać proporcje przestrzeni przydzielonej do ViewBoxinnej, która zacznie również skalować wysokość. Prawdopodobnie możesz obejść ten problem za pomocą Stretchof UniformToFill.

Luke Puplett
źródło