WPF TextBox and Scroll behavior
Asked Answered
T

2

12

I have a problem. I need to host grid with controls in ScrollViewer to prevent textbox from being either truncated or collapsed to zero-with at the UI. Also I want the with of textbox to be expanded when user change windows width. I'm setting Window's content to following code

<DockPanel>
    <TreeView DockPanel.Dock="Left" Width="150"/>
    <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock Text="Name" 
                       Margin="5" 
                       VerticalAlignment="Center"/>
            <TextBox Grid.Column="1"
                     Text="Some Name"
                     Margin="5"
                     VerticalAlignment="Center"
                     MinWidth="200"/>
        </Grid>
    </ScrollViewer>
</DockPanel>

All work fine, but when user types very long text in TextBox it is being expanded and horizontal scroll appears. Is there any easy way to limit TextBox maximum width and allow it to be expanded only when user changes window size.

Tripinnate answered 22/12, 2008 at 11:31 Comment(0)
S
38

The problem is that the parent elements are providing TextBox with as much space as it thinks it needs, and when more text is present it will expand instead of staying at the initial automatic size.

One solution here is to make another auto-sized element and bind the TextBox.Width to it:

<DockPanel>
    <TreeView Width="150" DockPanel.Dock="Left"/>
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <TextBlock Margin="5" VerticalAlignment="Center" Text="Name"/>
            <Border x:Name="b" Grid.Column="1" Margin="5"/>
            <TextBox Width="{Binding ActualWidth, ElementName=b}"
                     MinWidth="200"
                     Grid.Column="1"
                     Margin="5"
                     VerticalAlignment="Center"
                     Text="Some Name"/>
        </Grid>
    </ScrollViewer>
</DockPanel>

Note that we set the Margin property of the auto-sizing element (the Border). This is important because if it's not set, there will be a loop:

  1. Border width autosizes to Grid column width
  2. TextBox width resizes to Border.ActualWidth
  3. Grid column width resizes to TextBox width + TextBox margin
  4. Border width autosizes to Grid column width again

By setting the Margin to the same as the TextBox, the resizing of the TextBox won't affect the Grid size.

Soliloquize answered 22/12, 2008 at 20:55 Comment(2)
After tinkering with code based on Robert's solution, I found it useful to bind the MaxWidth of a textbox to the enclosing element. It seems to avoid problems with infinite-resize loops for some applications.Waistband
Works fine, but now the TextBox stays at its large size when the window is made smaller. Any fix for that?Restriction
C
2

Overriding TextBox.MeasureOverride like so worked for me:

protected override Size MeasureOverride(Size constraint)
{
    Size origSize = base.MeasureOverride(constraint);
    origSize.Width = MinWidth;
    return origSize;
}
Colossal answered 25/11, 2011 at 22:8 Comment(1)
And how do you link MinWidth to the enclosing Column?Rosannrosanna

© 2022 - 2024 — McMap. All rights reserved.