【问题标题】:How can I prioritize WPF textbox wrap over autosize?如何优先考虑 WPF 文本框换行而不是 autosize?
【发布时间】:2011-10-17 19:39:57
【问题描述】:

在很多情况下,我的面板或网格会自动调整大小,但如果它们包含 TextBoxTextWrapping="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>

我在 Stack Overflow here 上发现了一个类似的问题,但发布的最佳解决方案不允许 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 之外还有什么想法吗?

【问题讨论】:

  • 确保我理解了这个问题:您是说如果文本框可以支持 10 行文本,您希望它仅在输入第 11 行时才开始水平扩展?
  • @crazyarabian,正确,我只希望在输入第 n 行(超出可见范围)时进行水平扩展。就像我可以在文本框想要垂直滚动时触发一样,然后允许展开。
  • 为什么要让文本框水平展开?从可用性的角度来看,这没有多大意义,而且似乎令人困惑,因为预期的行为要么是 a) 垂直扩展,要么是 b) 垂直滚动
  • 在这个应用程序中水平扩展是有意义的,它的浮动窗口等等。几乎所有的控件(除了扩展器和画布)都有一个固定的垂直足迹,如果它们超出了,就滚动脚印。几乎所有输入控件都水平拉伸以填充可用区域。

标签: c# wpf textbox autosize


【解决方案1】:

虽然我不建议这样做,因为我认为它会给用户带来意想不到的行为,但这似乎可以满足您的要求:

XAML:

&lt;TextBox ... MinHeight="120" Width="200" SizeChanged="TextBox_SizeChanged" /&gt;

后面的代码:

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) 为了使其工作,您必须同时使用 MinHeightWidth 以允许扩展和 2) 20 的水平扩展只是我用于测试的任意值目的;您需要想出一种更可靠的方法来计算变量扩展值。

【讨论】:

  • +1 的想法,谢谢!如果它导致最终解决方案,我会接受。如果您添加 MaxHeight,则此解决方案可以正常工作,并且在达到最大宽度时会开始垂直滚动。主要问题是设置固定宽度,因此 TextBox 最初不会拉伸到网格,如果用户调整窗口大小,它也不会调整。
  • 没有使用这个解决方案,但我接受了这个解决方案,因为我采纳了您的可用性建议,导致了解决方案。
【解决方案2】:

我目前使用的解决方案是上面提到的边界技巧,并且解释得更好here。为了让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>

【讨论】:

    【解决方案3】:

    有一个简单的技巧可以让它工作。使用画布,然后将文本框的 width 绑定到画布的 actualwidth 并将画布的 height 绑定到 actualheight 的文本框。

    <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 继承父容器的宽度和子容器的高度。我正在考虑将模式包装在自定义控件中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多