TextBox расширяется с помощью Grid, но не с текстом

У окна есть Сетка с двумя столбцами. Левый столбец содержит элемент управления с постоянной шириной, но с адаптируемой высотой. Правый столбец содержит TextBox, который занимает все оставшееся пространство в Grid (и, следовательно, в Window).

Сетка имеет минимальную ширину и высоту и заключена в ScrollViewer. Если пользователь изменяет размер окна, чтобы он был меньше минимальной ширины/высоты сетки, отображаются полосы прокрутки.

Это именно то, как я хочу, чтобы это было. Однако проблема возникает, когда пользователь начинает печатать текст. Если текст слишком длинный, чтобы поместиться в одну строку в TextBox, я хочу, чтобы текст был перенесен. Поэтому я установил TextWrapping="Wrap" в TextBox. Но так как TextBox имеет автоматическую ширину и оборачивается в ScrollViewer (фактически это вся Grid, который обернут), TextBox просто продолжает расширяться вправо.

Я хочу, чтобы TextBox расширялся, если окно раскрыто, но я не хочу, чтобы TextBox расширялся за счет текста. Скорее текст должен обернуться внутри доступного TextBox. Если текст не помещается в пределах высоты TextBox, в TextBox должна отображаться полоса прокрутки.

Есть ли способ сделать это?

Ниже приведен код, который показывает мою проблему:

<Window x:Class="AdaptingTextBoxes.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="300" Width="400" Background="DarkCyan">
<Grid Margin="10" Name="LayoutRoot">
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Grid MinWidth="300" MinHeight="200">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="auto" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Button Grid.Column="0" Margin="0,0,10,0" Content="Button" Width="100" />

            <TextBox Grid.Column="1" AcceptsReturn="True" TextWrapping="Wrap" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" />
        </Grid>
    </ScrollViewer>
</Grid>
</Window>

Ответ 1

Вы можете использовать невидимую границу (ее взломанный, но он работает - как я склонен сортировать динамические размеры текстового поля):

<Border BorderThickness="0" x:Name="border" Grid.Column="1" Margin="0.5" />
                <TextBox Grid.Column="1" AcceptsReturn="True" TextWrapping="Wrap" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}" />

Ответ 2

Вы пытались установить свойство MaxWidth только в TextBox?

Изменить после комментария OP

Я попытался бы избавиться от ScrollViewer. Размер, используемый в макете Grid, должен позаботиться о повторной калибровке, а настройки полосы прокрутки на TextBox должны позаботиться об остальном.

Ответ 3

Ответ основан на ответе Леома.

Решение отлично работает, когда вы увеличиваете окно, но изменение размера не является гладким, когда вы делаете окно меньше. Поскольку текстовое поле участвует в макете сетки, оно должно выполнять процесс компоновки несколько раз. Вы можете исправить это, поместив texbox в холст, так что изменение размера текстового поля больше не вызывает повторную компоновку сетки.

Обновленный код:

<Border BorderThickness="0" x:Name="border" Grid.Column="1" Margin="0.5" />
<Canvas Grid.Column="1">
    <TextBox AcceptsReturn="True" TextWrapping="Wrap" Width="{Binding ActualWidth, ElementName=border}" Height="{Binding ActualHeight, ElementName=border}" />
</Canvas>