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

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

Textbox expanding the panel

Я хочу, чтобы 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 с измененным поведением?

Ответ 1

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

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 - это просто произвольное значение, которое я использовал для тестирования цели; вам нужно придумать более надежный способ вычисления значения переменной.

Ответ 2

Есть простой трюк, чтобы заставить его работать. Используйте 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>

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

enter image description here

и изменить размер

enter image description here

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

Ответ 3

Решение, с которым я собираюсь в данный момент, - это трюк с границами, упомянутый выше, и объяснил лучше здесь. Чтобы 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>