Как я могу установить приоритет обтекания текстового поля WPF над автоматическим изменением размера?

У меня есть ряд ситуаций, когда у меня есть панели или сетки, размер которых изменяется автоматически, но если они содержат TextBox с TextWrapping="Wrap", TextBox продолжает расширять панель / сетку вправо задолго до того, как это действительно нужно, например, на изображении ниже:

Текстовое поле при раскрытии панели

Я хочу, чтобы TextBox заполнил свою область, обернув текст, прежде чем он попытается развернуться вправо. Упрощенный пример проблемы:

<Grid>
    <Grid Background="Black" />
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <TextBox TextWrapping="Wrap" Height="120" MinWidth="200" />
    </Grid>
</Grid>

Я нашел аналогичный вопрос о переполнении стека здесь, но лучшее опубликованное решение не позволило TextBox расшириться. Это решение было примерно таким:

<Grid>
    <Grid Background="Black">
    </Grid>
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Border BorderThickness="0" x:Name="border" Margin="0.5" />
        <TextBox TextWrapping="Wrap" Height="120" MinWidth="200" Width="{Binding ActualWidth, ElementName=border}" />
    </Grid>
</Grid>

Есть какие-нибудь идеи, кроме расширения TextBox измененным поведением?


person Dave Clemmer    schedule 01.08.2011    source источник
comment
Убедившись, что я понимаю вопрос: вы говорите, что если текстовое поле может поддерживать 10 строк текста, вы хотите, чтобы оно начинало расширяться по горизонтали только при вводе 11-й строки?   -  person sellmeadog    schedule 02.08.2011
comment
@crazyarabian, правильно, мне нужно только горизонтальное расширение, когда вводится n-я строка (за пределами видимой). Как-то так, если бы я мог срабатывать, когда текстовое поле хотело прокручиваться по вертикали, а затем разрешало расширение.   -  person Dave Clemmer    schedule 02.08.2011
comment
почему вы хотите, чтобы текстовое поле расширялось по горизонтали? с точки зрения удобства использования это не имеет особого смысла и может сбивать с толку, поскольку ожидаемым поведением будет а) вертикальное расширение или б) вертикальная прокрутка.   -  person sellmeadog    schedule 02.08.2011
comment
В этом приложении имеет смысл расширяться по горизонтали с его плавающими окнами и т. Д. Почти все элементы управления (за исключением расширителей и холстов) имеют фиксированную вертикальную площадь и прокручиваются, если выходят за пределы этой площади. Почти все элементы управления вводом растягиваются по горизонтали, чтобы заполнить доступную область.   -  person Dave Clemmer    schedule 02.08.2011


Ответы (3)


Хотя я бы не рекомендовал это делать, поскольку я думаю, что это приводит к неожиданному поведению пользователя, похоже, это достигает того, о чем вы просите:

XAML:

<TextBox ... MinHeight="120" Width="200" SizeChanged="TextBox_SizeChanged" />

Код позади:

private void TextBox_SizeChanged(object sender, SizeChangedEventArgs e)
{
    try
    {
        if (e.PreviousSize == Size.Parse("0,0")) return;
        if (e.PreviousSize == e.NewSize) return;

        if (e.HeightChanged)
        {
            ((TextBox)sender).Width = e.PreviousSize.Width + 20;
        }
    }

    finally
    {
        e.Handled = true;
    }
}

Следует отметить пару вещей: 1) для того, чтобы это сработало, вы должны одновременно использовать MinHeight и Width, чтобы разрешить расширение, и 2) горизонтальное расширение 20 - это просто произвольное значение, которое я использовал для целей тестирования; вы захотите придумать более надежный способ вычисления значения расширения переменной.

person sellmeadog    schedule 01.08.2011
comment
+1 за идею, спасибо! Я согласен, если это приведет к окончательному решению. Это решение отлично работает, если вы добавляете MaxHeight, и вертикальная прокрутка срабатывает при достижении максимальной ширины. Основная проблема заключается в установке фиксированной ширины, поэтому TextBox изначально не растягивается до сетки и не регулируется, если пользователь изменяет размер окна. - person Dave Clemmer; 02.08.2011
comment
Я не использовал это решение, но принял его как решение, так как я принял ваши предложения по удобству использования, которые привели к решению. - person Dave Clemmer; 02.08.2011

Есть простой трюк, чтобы заставить его работать. Используйте Canvas, а затем привяжите ширину текстового поля к фактической ширине холста, а высоту холста к фактической высоте текстового поля.

<Canvas 
    x:Name="Canvas" 
    Height="{Binding ElementName=TextBlock, Path=ActualHeight}" 
    VerticalAlignment="Stretch" HorizontalAlignment="Stretch">

        <TextBlock
            x:Name="TextBlock"
            Width="{Binding ElementName=Canvas, Path=ActualWidth}"
            TextWrapping="WrapWithOverflow"
            Text="blah blah blah blah" />


</Canvas>

Снимки экрана нашего производственного приложения, использующего его

введите описание изображения здесь

и размер изменен

введите описание изображения здесь

Хитрость в том, что Canvas наследует ширину от родительского контейнера и высоту от дочернего. Я подумываю обернуть шаблон в настраиваемый элемент управления.

person bradgonesurfing    schedule 27.03.2015

Решение, к которому я сейчас прибегаю, - это упомянутый выше трюк с границами, который лучше объяснил здесь < / а>. Чтобы TextBox автоматически заполнял область в Grid и изменял свой размер, когда пользователь увеличивает или уменьшает окно, поле границы заполнителя должно быть больше, чем поле TextBox.

Это решение не расширяется автоматически по горизонтали, как изначально желалось, но оно лучше, чем отдельная строка текста, расширяющаяся до нужной области.

Пример xaml панели на изображении выше с трюком с границами (поля текстовых полей равны 5):

<Grid>
    <!-- Diagram Window -->
    <Expander Header="{Binding Source={StaticResource labels}, Path=DiagramToolBoxHeader}" IsExpanded="True">
        <Grid MinWidth="200" MinHeight="200">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto" ></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="10"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Style="{StaticResource LabelHeader}" Content="{Binding Title}" />
            <Label Grid.Row="1" Grid.Column="1" Style="{StaticResource SolutionDiagramNameInput}" Content="{Binding SolutionDiagramNameLabel}" />
            <Label Grid.Row="2" Grid.Column="1" Style="{StaticResource DescriptionInput}" Content="{Binding DescriptionLabel}" />
            <TextBox Grid.Row="1" Grid.Column="2" Text="{Binding SolutionDiagramName, Mode=TwoWay}" />
            <Border Name="PlaceHolderBorder" Grid.Column="2" Margin="7"/>
            <TextBox Grid.Row="2" Grid.Column="2" Text="{Binding Description, Mode=TwoWay}" VerticalScrollBarVisibility="Auto"
                     TextAlignment="Left" TextWrapping="Wrap" Width="{Binding ElementName=PlaceHolderBorder, Path=ActualWidth}" />
            <StackPanel Orientation="Horizontal" Grid.Row="3" Grid.Column="2" Margin="5">
                <Button Command="{Binding UpdateCommand}" Content="{Binding UpdateButtonLabel}"></Button>
                <Button Command="{Binding ResetCommand}" Content="{Binding ResetButtonLabel}"></Button>
                <Button Command="{Binding DefaultsCommand}" Content="{Binding DefaultsButtonLabel}"></Button>
                <Button Command="{Binding CloseConfirmCommand}" Content="{Binding CloseButtonLabel}"></Button>
            </StackPanel>
        </Grid>
    </Expander>
</Grid>
person Dave Clemmer    schedule 02.08.2011