ScrollViewer и обтекание TextBlock
У меня есть следующий макет (упрощенно):
<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 больше не переносится.
4 ответа
Просто дайте TextBlock
MaxWidth
какой ActualWidth
либо из GroupBox
или в вашем случае даже layoutGrid
(как твой 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" />
Я создал контрольную оболочку 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>
У меня были данные TextBlocks, связанные в<ItemsControl>
и хотел, чтобы они складывались вертикально, как чат. Более длинные текстовые блоки не переносились.
я изменил<ScrollViewer>
HorizontalScrollBarVisibility
отHidden
кDisabled
. Это привело к переносу TextBlocks между строками даже при изменении размера:
<ScrollViewer
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled">
<ItemsControl
VerticalAlignment="Stretch"
Height="Auto" >
Если вы думаете о своей ситуации логически, то вы поймете, что, конечно, TextBlock
без его Width
набор свойств не будет перенесен, когда помещен внутрь ScrollViewer
, TextBlock
может обернуть его текст, только если сказано, когда начинать обтекание... словом "когда", я действительно имею в виду "где". Нужно сказать, что "в 150 пикселях слева, начните обтекание текстового содержимого".
Теперь мы можем сказать это сделать это так:
<TextBlock Text="Some random long text string that is longer than 150 pixels long"
TextWrapping="Wrap" Width="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
ограничение на это, оно никогда не закутается.