WPF: Setting the Width (and Height) as a Percentage Value

354,058

Solution 1

The way to stretch it to the same size as the parent container is to use the attribute:

 <Textbox HorizontalAlignment="Stretch" ...

That will make the Textbox element stretch horizontally and fill all the parent space horizontally (actually it depends on the parent panel you're using but should work for most cases).

Percentages can only be used with grid cell values so another option is to create a grid and put your textbox in one of the cells with the appropriate percentage.

Solution 2

You can put the textboxes inside a grid to do percentage values on the rows or columns of the grid and let the textboxes auto-fill to their parent cells (as they will by default). Example:

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

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

This will make #1 2/5 of the width, and #2 3/5.

Solution 3

Typically, you'd use a built-in layout control appropriate for your scenario (e.g. use a grid as a parent if you want scaling relative to the parent). If you want to do it with an arbitrary parent element, you can create a ValueConverter do it, but it probably won't be quite as clean as you'd like. However, if you absolutely need it, you could do something like this:

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

Which can be used like this, to get a child textbox 10% of the width of its parent canvas:

<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>

Solution 4

For anybody who is getting an error like : '2*' string cannot be converted to Length.

<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>

Solution 5

IValueConverter implementation can be used. Converter class which takes inheritance from IValueConverter takes some parameters like value (percentage) and parameter (parent's width) and returns desired width value. In XAML file, component's width is set with the desired value:

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>
Share:
354,058

Related videos on Youtube

Andreas Grech
Author by

Andreas Grech

+++++[&gt;+++++[&gt;++++&lt;-]&lt;-]&gt;&gt;+++.--..++++++. Contactable at $(echo qernfterpu#tznvy?pbz | tr ?a-z# .n-za-m@)

Updated on December 11, 2020

Comments

  • Andreas Grech
    Andreas Grech over 3 years

    Say I want a TextBlock to have its Width equal to it's Parent container's Width (ie, stretch from side to side) or a percentage of it's Parent Container Width, how can I accomplish this in XAML without specifying absolute values?

    I want to do this so that if the Parent Container container is later on expanded (its' Width increased), its' Child Elements will also be expanded automatically. (basically, like in HTML and CSS)

    • Jesper Fyhr Knudsen
      Jesper Fyhr Knudsen about 15 years
      Have a look at this answer.
    • Shimmy Weitzhandler
      Shimmy Weitzhandler over 14 years
      Use cwap's answer and include the tb in a grid setting it's alignment to stretch.
  • Andreas Grech
    Andreas Grech about 15 years
    I already tried that, but I'm getting this error: '2*' string cannot be converted to Length.'
  • Shimmy Weitzhandler
    Shimmy Weitzhandler over 14 years
    Your answer helped me a lot, thanks! I tried to figure out what the * does for years, you explained it so short and good.
  • EightyOne Unite
    EightyOne Unite over 13 years
    :-) ,... the * is called "star"
  • Pratik Deoghare
    Pratik Deoghare over 13 years
    Actually, *(Asterisk) is little star ;) etymonline.com/index.php?term=asterisk
  • Jeremy
    Jeremy about 13 years
    This is really cool, how can I do it in code (set the width of the textbox)?
  • Denys Wessels
    Denys Wessels over 10 years
    My mom says I'm a star
  • Darren
    Darren about 10 years
    This does not work, even if the TextBox is in a Grid. The width can be set to a Double, Qualified Double (A double value followed by px, in, cm or pt) or Auto. See msdn.microsoft.com/en-GB/library/…
  • cwap
    cwap about 10 years
    Yes.. This is actually a very poor reply, but based on all the upvotes, I suppose it helped someone (was a long time ago), which is why I haven't deleted it.
  • Ben
    Ben almost 10 years
    Why not <RowDefinition Height="auto" />?
  • Flat Eric
    Flat Eric over 9 years
    You should consider adding CultureInfo.InvariantCulture to the double conversion because the parameter is regarded as string and in cultures with different decimal separator it will not work as expected.
  • Yama
    Yama over 9 years
    "auto" takes only as much space as the control needs
  • Mafii
    Mafii about 8 years
    Thank you so much, this should be the top answer.
  • Knut Valen
    Knut Valen about 8 years
    This is definitely the best answer.
  • Norman
    Norman over 6 years
    Now that we're at the end of '17, 2* 3* is absolutely valid. Even the Visual Studio GUI provides fields to specify such values.
  • prw56
    prw56 about 4 years
    Just wanted to offer another confirmation that this does work with newer xaml versions