WPF - 复杂的 TextBlock 布局
WPF - Complex TextBlock layout
在过去的几天里,我一直在努力思考以下 TextBlocks 布局:
-------------------- -----------
| 1 | | |
-------------------- | 3 |
| 2 | | |
----------------- -----------
所有 TextBlock 都具有动态宽度。它们具有固定的高度并位于固定大小的容器中。他们需要满足以下要求:
- 2 具有最高优先级 - 它需要始终保持全长。
- 3可以填满上浆后剩下的space 2.
当忽略 TextBlock 1 时,这两个要求可以通过将其他两个 TextBlock 放在一个网格中来满足,列分别设置为 "auto" 和“*”。
还有第三个要求:
- 1 假设所有 space 它可以,但不限制 3.
示例:
块 3 中的长内容(块 2 内容是全长,块 3 内容被修剪):
----------------- -------------
| 1 | | |
----------------- | 3 |
| 2 | | |
----------------- -------------
块3中的短内容(块2和3内容都是全长;块1填充剩余的space):
--------------------- ---------
| 1 | | |
--------------------- | 3 |
| 2 | | |
----------------- ---------
有没有办法在 WPF 中实现这种布局?怎么样?
我认为纯 XAML 不可能做到这一点。实现您的要求的一种方法是实施您自己的面板,该面板可以执行所有操作。这是一种实现方式:
public class SpecialPanel : Panel
{
protected override Size MeasureOverride (Size constraint)
{
foreach (UIElement child in Children)
{
child.Measure (constraint);
}
return constraint;
}
protected override Size ArrangeOverride (Size arrangeSize)
{
if (VisualChildrenCount != 3)
{
return (arrangeSize);
}
Size sizeLabel0 = InternalChildren[0].DesiredSize;
Size sizeLabel1 = InternalChildren[1].DesiredSize;
Size sizeLabel2 = InternalChildren[2].DesiredSize;
InternalChildren[1].Arrange (new Rect (0, sizeLabel0.Height, sizeLabel1.Width, sizeLabel1.Height));
var maxRemainingWidthFor2 = arrangeSize.Width - sizeLabel1.Width;
if (maxRemainingWidthFor2 <= 0)
{
InternalChildren[0].Arrange (new Rect (0, 0, sizeLabel0.Width, sizeLabel0.Height));
}
else
{
if (maxRemainingWidthFor2 < sizeLabel2.Width)
{
InternalChildren[2].Arrange (new Rect (arrangeSize.Width - maxRemainingWidthFor2, 0, maxRemainingWidthFor2, sizeLabel2.Height));
InternalChildren[0].Arrange (new Rect (0, 0, Math.Min (sizeLabel0.Width, sizeLabel1.Width), sizeLabel0.Height));
}
else
{
var max0 = arrangeSize.Width - maxRemainingWidthFor2;
var width0 = Math.Min (sizeLabel0.Width, max0);
InternalChildren[2].Arrange (new Rect (arrangeSize.Width - sizeLabel2.Width, 0, sizeLabel2.Width, sizeLabel2.Height));
InternalChildren[0].Arrange (new Rect (0, 0, arrangeSize.Width - sizeLabel2.Width, sizeLabel0.Height));.
}
}
return arrangeSize;
}
}
用法:
<local:SpecialPanel>
<Label
x:Name="Label1"
VerticalContentAlignment="Center"
Content="TextBlock00000000000000" />
<Label
x:Name="Label2"
VerticalContentAlignment="Center"
Content="TextBloc111111111111" />
<Label
x:Name="Label3"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Content="Label333333" />
</local:SpecialPanel>
在过去的几天里,我一直在努力思考以下 TextBlocks 布局:
-------------------- -----------
| 1 | | |
-------------------- | 3 |
| 2 | | |
----------------- -----------
所有 TextBlock 都具有动态宽度。它们具有固定的高度并位于固定大小的容器中。他们需要满足以下要求:
- 2 具有最高优先级 - 它需要始终保持全长。
- 3可以填满上浆后剩下的space 2.
当忽略 TextBlock 1 时,这两个要求可以通过将其他两个 TextBlock 放在一个网格中来满足,列分别设置为 "auto" 和“*”。
还有第三个要求:
- 1 假设所有 space 它可以,但不限制 3.
示例:
块 3 中的长内容(块 2 内容是全长,块 3 内容被修剪):
----------------- -------------
| 1 | | |
----------------- | 3 |
| 2 | | |
----------------- -------------
块3中的短内容(块2和3内容都是全长;块1填充剩余的space):
--------------------- ---------
| 1 | | |
--------------------- | 3 |
| 2 | | |
----------------- ---------
有没有办法在 WPF 中实现这种布局?怎么样?
我认为纯 XAML 不可能做到这一点。实现您的要求的一种方法是实施您自己的面板,该面板可以执行所有操作。这是一种实现方式:
public class SpecialPanel : Panel
{
protected override Size MeasureOverride (Size constraint)
{
foreach (UIElement child in Children)
{
child.Measure (constraint);
}
return constraint;
}
protected override Size ArrangeOverride (Size arrangeSize)
{
if (VisualChildrenCount != 3)
{
return (arrangeSize);
}
Size sizeLabel0 = InternalChildren[0].DesiredSize;
Size sizeLabel1 = InternalChildren[1].DesiredSize;
Size sizeLabel2 = InternalChildren[2].DesiredSize;
InternalChildren[1].Arrange (new Rect (0, sizeLabel0.Height, sizeLabel1.Width, sizeLabel1.Height));
var maxRemainingWidthFor2 = arrangeSize.Width - sizeLabel1.Width;
if (maxRemainingWidthFor2 <= 0)
{
InternalChildren[0].Arrange (new Rect (0, 0, sizeLabel0.Width, sizeLabel0.Height));
}
else
{
if (maxRemainingWidthFor2 < sizeLabel2.Width)
{
InternalChildren[2].Arrange (new Rect (arrangeSize.Width - maxRemainingWidthFor2, 0, maxRemainingWidthFor2, sizeLabel2.Height));
InternalChildren[0].Arrange (new Rect (0, 0, Math.Min (sizeLabel0.Width, sizeLabel1.Width), sizeLabel0.Height));
}
else
{
var max0 = arrangeSize.Width - maxRemainingWidthFor2;
var width0 = Math.Min (sizeLabel0.Width, max0);
InternalChildren[2].Arrange (new Rect (arrangeSize.Width - sizeLabel2.Width, 0, sizeLabel2.Width, sizeLabel2.Height));
InternalChildren[0].Arrange (new Rect (0, 0, arrangeSize.Width - sizeLabel2.Width, sizeLabel0.Height));.
}
}
return arrangeSize;
}
}
用法:
<local:SpecialPanel>
<Label
x:Name="Label1"
VerticalContentAlignment="Center"
Content="TextBlock00000000000000" />
<Label
x:Name="Label2"
VerticalContentAlignment="Center"
Content="TextBloc111111111111" />
<Label
x:Name="Label3"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Content="Label333333" />
</local:SpecialPanel>