ScrollViewer和TextBlock包装

时间:2013-12-12 10:45:27

标签: wpf wpf-4.0

我有以下布局(简化):

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition MaxWidth="400" />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>

  <!-- Code for Column=0 -->

  <ScrollViewer Grid.Column="1">
    <Grid x:Name="layoutGrid">

      <Grid.ColumnDefinitions>
        <Grid.ColumnDefinition Width="Auto" />
        <Grid.ColumnDefinition MinWidth="100" MaxWidth="400" />
        <Grid.ColumnDefinition Width="Auto" />
      </Grid.ColumnDefinitions>

      <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition />
      </Grid.RowDefinitions>


      <!-- Code for Row=0 and Row=1 -->

      <GroupBox Grid.ColumnSpan="3" Grid.Row=2>
        <TextBlock Text="{Binding ...}" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Top" />
      </GroupBox>
    </Grid>
  </ScrollViewer>
</Grid>
  • 第一列应该占据所需的空间(有时它可以是100像素,有时是500)。
  • 第二列应伸展到可用空间,但不超过400像素(变得难看)。
  • 第三列应占用所需空间(有时可能是200像素,有时是400像素)。
  • 如果在极少数情况下,layoutGrid需要的空间超出屏幕上的可用空间,则应该可以看到水平滚动条。
  • GroupBox应该始终具有所有三列的总宽度(它应该尽可能多地扩展它们的宽度)。在那个空间里,文本框应该换行。 GroupBox不应该伸展到屏幕上可用的整个空间。

我如何在xaml中实现这一目标?似乎只要插入了ScrollViewer,TextBlock就不再包装了。

3 个答案:

答案 0 :(得分:5)

只需给TextBlock MaxWidth ActualWidth GroupBoxlayoutGrid,或GroupBox TextBlock Width <GroupBox x:Name="grpBox" Grid.Row="2" Grid.ColumnSpan="3"> <TextBlock MaxWidth="{Binding ElementName=grpBox, Path=ActualWidth}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding ...}" TextWrapping="Wrap" /> </GroupBox> 具有相同的宽度)。这会迫使<TextBlock MaxWidth="{Binding ElementName=layoutGrid, Path=ActualWidth}" HorizontalAlignment="Left" VerticalAlignment="Top" Text="{Binding ...}" TextWrapping="Wrap" /> 在{{1}}超出该维度时进行换行,从而满足您的要求。

类似于:

{{1}}

{{1}}

答案 1 :(得分:0)

如果您从逻辑上考虑您的情况,那么您将理解当然TextBlock没有Width属性集在放入ScrollViewer时不会换行。如果TextBlock被告知什么时候开始包装,那么<TextBlock Text="Some random long text string that is longer than 150 pixels long" TextWrapping="Wrap" Width="150" /> 只能包装它的文本...'when',我的意思是'在哪里'。需要告诉他们,“从左边150像素开始包装文本内容”。

现在我们可以告诉它这样做:

<TextBlock Text="Some random long text string that is longer than 150 pixels long" 
    TextWrapping="Wrap" MaxWidth="150" />

或者像这样:

<Grid Width="150">
    <TextBlock Text="Some random long text string that is longer than 150 pixels long" 
    TextWrapping="Wrap" />
</Grid>

或者像这样:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150" />
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Text="Some random long text string that is longer than 
        150 pixels long" TextWrapping="Wrap" />
</Grid>

或者像这样:

Width

但是,如果您删除TextBlock限制,那么Text将永远不会知道何时应该开始包裹TextBlock。通过将ScrollViewer放入Width,您可以告诉它它具有可能需要的所有空间,因此,如果不对其设置{{1}}限制,它将永远不会包裹

答案 2 :(得分:0)

我为此创建了一个控件包装器IgnoreWidthControl

public class IgnoreWidthControl : ContentControl
{
    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        base.OnRenderSizeChanged(sizeInfo);
        if (sizeInfo.WidthChanged)
            InvalidateMeasure();
    }

    protected override Size MeasureOverride(Size constraint)
    {
        constraint.Width = ActualWidth;
        Size size = new Size();
        UIElement child = GetFirstVisualChild();
        if (child != null)
        {
            child.Measure(constraint);
            size.Height = child.DesiredSize.Height;
        }

        return size;
    }

    private UIElement GetFirstVisualChild()
    {
        if (this.VisualChildrenCount <= 0)
            return null;
        return this.GetVisualChild(0) as UIElement;
    }
}

示例使用:

<myc:IgnoreWidthControl>
    <TextBlock Text="Very long text which has to be wrapped. Yeah, it must be wrapped." TextWrapping="Wrap" />
</myc:IgnoreWidthControl>