ScrollViewer and TextBlock wrapping

限于喜欢 提交于 2019-12-12 14:46:23

问题


I have the following layout (simplified):

<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>
  • First column should occupy space as mush as it needs (sometimes it can be 100 pixels, sometimes 500).
  • Second column Should stretch to available space, but no more than 400 pixels (gets ugly).
  • Third column should occupy space as much as it needs (sometimes it can be 200 pixels, sometimes 400).
  • If, in some rare cases, layoutGrid needs space more than available on the screen, horizontal scrollbar should be visible.
  • GroupBox should always have the total width of all three columns (it should spread as much as their width is in total). And in that space, text box should wrap. GroupBox should not stretch to whole space available on screen.

How can I achieve this in xaml? It seems that as soon as ScrollViewer is inserted, TextBlock does not wrap any more.


回答1:


Just give the TextBlock a MaxWidth which is the ActualWidth of either the GroupBox or in your case even the layoutGrid (as your GroupBox has the same width). This would force the TextBlock to have to wrap when it's Width exceeds that dimension and thereby giving you your requirement.

So something like:

<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>

or

<TextBlock MaxWidth="{Binding ElementName=layoutGrid,
                              Path=ActualWidth}"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Text="{Binding ...}"
            TextWrapping="Wrap" />



回答2:


I have created a control wrapper IgnoreWidthControl for this purpose:

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;
    }
}

And the example use:

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



回答3:


If you think about your situation logically, then you'll understand that of course a TextBlock without its Width property set will not wrap when put inside a ScrollViewer. A TextBlock can only wrap its text if it is told when to start wrapping... by 'when', I really mean 'where'. It needs to be told, 'at 150 pixels from the left, start wrapping the text content'.

Now we can tell it to do that like this:

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

Or like this:

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

Or like this:

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

Or like this:

<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>

However, if you remove the Width restriction, then the TextBlock will never know when it should start wrapping the Text. By putting your TextBlock into a ScrollViewer, you are telling it that it has all the space that it could possibly want and therefore, without setting a Width restriction on it, it will never wrap.



来源:https://stackoverflow.com/questions/20541299/scrollviewer-and-textblock-wrapping

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!