Textbox will not stretch to fill viewbox

17,646

Solution 1

I think what you want is not easily possible. ViewBox tells its children that they have inifite space, in the measure pass of the layouting. After that, the display is fit into the viewbox. Now a textbox, told to have infinite space, obviously can't stretch. I have 2 solutions, which i think are not what you want, but might be helpful anyway.

The first:

<Viewbox Grid.Column="1" Grid.Row="0" Stretch="Uniform" >
    <Grid Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Viewbox}}, Path=ActualWidth}">
      <TextBox TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
    </Grid>
</Viewbox>

this will stretch you textbox infact, but disable the behaviour expected from the viewbox. Why? We told the ViewBox to keep the aspect ratio, and set the textbox to fill the whole width of the viewbox, which keeps the size of the textbox.

The second:

would be to add a height to the grid, taken from the label, modified with the scaletransform of its viewbox.

This one i haven't tried, but it would involve a value converter.

In conclusion: There is no easy way to achieve what you want, because of the way the viewbox layouts its children. If you just want to stretch horizontally, my first solution works fine, if you want to scale. My guess is you have to do it yourself.

Solution 2

If what you want doesn't work/isn't easy then fake it:

    <TextBox GotFocus="TextBox_GotFocus" HorizontalAlignment="Stretch" BorderThickness="0" Grid.Column="1"/>
    <Viewbox HorizontalAlignment="Left" Stretch="Uniform" Grid.Column="1">
        <TextBox x:Name="NameTextBox" Width="50" TextWrapping="Wrap" Text="Text" BorderThickness="0"/>
    </Viewbox>

    private void TextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        NameTextBox.Focus();
        NameTextBox.SelectionStart = NameTextBox.Text.Length;
    }

Basically what happens is another TextBox is behind the Viewbox and when the behind TextBox gets focus, it switches focus to the Viewbox's TextBox. This will produce some odd resizing since you have your grid setup with relative sizes. You will need to play around with your grid column/width sizes until you get the effect you desire.

Solution 3

Just use a converter

Set the FontSize like this: FontSize="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight ,Converter={StaticResource heightconverter}, ConverterParameter=3}"

public class ProcentualHeightConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (parameter is string p)
        {
            if (value is double v)
            {
                var result = double.TryParse(p, out double param);
                if (result)
                {
                    return v / param;
                }
            }
        } 
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Share:
17,646
Blake Mumford
Author by

Blake Mumford

Hi, I'm a junior doctor and I enjoy programming in my spare time. Having spent a lot of time learning how to use WPF, I have decided to make the move to web programming. My current project is a medical records program which I hope one day will be a viable commercial package.

Updated on June 04, 2022

Comments

  • Blake Mumford
    Blake Mumford about 2 years

    I want the font size of my labels and textboxes in my LOB form to grow and shrink with window resize or resolution change. To achieve this I've placed my labels and textboxes within viewboxes.

    The labels and custom radio buttons behave as I expect, but the textboxes will not stretch horizontally to fill the viewbox (sorry can't post image because of rep). The textboxes will horizontally fill the viewbox if you type into them.

    Here is an example of the code which I am working with:

      <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.186*"/>
                <ColumnDefinition Width="0.814*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="0.127*"/>
                <RowDefinition Height="0.873*"/>
            </Grid.RowDefinitions>
            <Viewbox Margin="0,0,0.917,0">
                <Label Content="First name:"/>
            </Viewbox>
            <Viewbox Grid.Column="1">
                <TextBox TextWrapping="Wrap"/>
            </Viewbox>
        </Grid>
    

    I've tried placing grid, stackpanel and dockpanel (with LastChildFill="True") within the viewbox and then placing the textboxes within these layout controls but this didn't work either. Is there anyway to get the textboxes to horizontally fill the parent viewbox?

    This problem is similar to this: WPF TextBox won't fill in StackPanel but this problem is with stackpanels, not viewboxes.

  • N_A
    N_A over 12 years
    A warning about binding to the AcutalWidth or the ActualHeight: "Because ActualHeight is a calculated value, you should be aware that there could be multiple or incremental reported changes to it as a result of various operations by the layout system. The layout system may be calculating required measure space for child elements, constraints by the parent element, and so on." This can cause any bindings to ActualHeight or ActualWidth to fire multiple times per resize. This will have a performance impact if there are too many of these bindigs.
  • dowhilefor
    dowhilefor over 12 years
    +1 Of course you are right and its worth pointing out, but in this case i don't know of a better solution.
  • N_A
    N_A over 12 years
    Ha Ha! I did it without actualwidth!
  • Blake Mumford
    Blake Mumford over 12 years
    Thanks for the answer. You're right, the first option does break the viewbox and I don't think there is an easy answer to this problem. I think I might come back to it later once I've learned more about WPF. Thanks again!
  • Nicolas
    Nicolas about 4 years
    Due to the flaws of dowhilefor's answer above, I prefer this one - additionally this is even simpler! (but it's a pity that WPF fails that bad here...)