【发布时间】:2017-10-10 12:56:04
【问题描述】:
我有两个自定义控件用于显示 cmets 和签名的集合。这些控件中的每一个都有一个用于更改显示样式的按钮 - 显示整个集合或仅显示前 4 个元素。
当我将这些控件放在默认的 WrapPanel 中时,它们可以正常工作:根据用户的操作展开或折叠。 在我自己的带有新 ArrangeOverride 功能的自定义 WrapPanel 中,它们也可以正常工作。
现在我需要带有选项“LastChildFill”(我在这里找到示例)和自定义“WrapDirection”(类似于 FlowDirection)的 WrapPanel。 WrapPanel 中的第一个或最后一个元素必须填充所有剩余空间,而它大于元素的 MinWidth。 所以我用自定义的 MeasureOverride 和 ArrangeOverride 创建了第三个 WrapPanel。它可以按我的意愿工作,但是当我更改控件显示样式时,控件内的集合会更改,但是 WrapPanel 中的 MeasureOverride 在我更改窗口大小之前不会启动。
更新:MeasureOverride 不会开始扩展填充剩余空间的第一个或最后一个元素。折叠此元素效果很好。
我不明白自定义 MeasureOverride 破坏了什么?
更新 2: 我觉得我的问题与此类似:MeasureOverride not always called on children's property changes。
并附上 MeasureOverride 代码。
public class WrapPanelFlowDirection : WrapPanel
{
public bool LastChildFill
{
get { return (bool)GetValue(LastChildFillProperty); }
set { SetValue(LastChildFillProperty, value); }
}
public static readonly DependencyProperty LastChildFillProperty =
DependencyProperty.Register("LastChildFill", typeof(bool), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsMeasure));
public WrapDirection WrapDirection
{
get { return (WrapDirection)GetValue(WrapDirectionProperty); }
set { SetValue(WrapDirectionProperty, value); }
}
public static readonly DependencyProperty WrapDirectionProperty =
DependencyProperty.Register("WrapDirection", typeof(WrapDirection), typeof(WrapPanelFlowDirection), new FrameworkPropertyMetadata(WrapDirection.LeftToRight, FrameworkPropertyMetadataOptions.AffectsMeasure));
#region Measure Override
protected override Size MeasureOverride(Size availableSize)
{
var panelSize = new Size(availableSize.Width, 0);
double minWidth = 0;
foreach (FrameworkElement child in this.InternalChildren)
{
child.Measure(availableSize);
minWidth += child.DesiredSize.Width;
}
int firstChildInLine = 0;
double currLineHeight = 0;
double currLineWidth = 0;
UIElementCollection children = this.InternalChildren;
for (int i = 0; i < children.Count; i++)
{
FrameworkElement child = children[i] as FrameworkElement;
if (child == null)
continue;
double w = 0;
if (child.MinWidth == 0)
w = child.DesiredSize.Width;
else
w = child.MinWidth;
if (currLineWidth + w <= availableSize.Width)
{
currLineWidth += w;
currLineHeight = Math.Max(currLineHeight, child.DesiredSize.Height);
}
else
{
MeasureOneLine(firstChildInLine, i - 1, ref currLineHeight, availableSize.Width);
panelSize.Height += currLineHeight;
currLineWidth = w;
currLineHeight = child.DesiredSize.Height;
if (w > availableSize.Width)
{
MeasureOneLine(i, i, ref currLineHeight, availableSize.Width);
panelSize.Height += currLineHeight;
currLineHeight = currLineWidth = 0;
firstChildInLine = i + 1;
}
else
{
firstChildInLine = i;
}
}
}
if (firstChildInLine < children.Count)
{
MeasureOneLine(firstChildInLine, children.Count - 1, ref currLineHeight, availableSize.Width);
panelSize.Height += currLineHeight;
}
if (double.IsInfinity(panelSize.Width))
panelSize.Width = minWidth;
return panelSize;
}
private void MeasureOneLine(int start, int end, ref double height, double totalWidth)
{
UIElementCollection children = this.InternalChildren;
if (WrapDirection == WrapDirection.LeftToRight)
{
for (int i = start; i < end; i++)
{
FrameworkElement child = children[i] as FrameworkElement;
if (child == null)
continue;
double w = 0;
if (child.MinWidth == 0)
w = child.DesiredSize.Width;
else
w = child.MinWidth;
if (i < end)
{
child.Measure(new Size(w, height));
totalWidth -= w;
}
else
{
child.Measure(new Size(totalWidth, double.PositiveInfinity));
height = Math.Max(height, child.DesiredSize.Height);
}
}
}
else
{
for (int i = end; i >= start; i--)
{
FrameworkElement child = children[i] as FrameworkElement;
if (child == null)
continue;
double w = 0;
if (child.MinWidth == 0)
w = child.DesiredSize.Width;
else
w = child.MinWidth;
if (i > start)
{
child.Measure(new Size(w, height));
totalWidth -= w;
}
else
{
child.Measure(new Size(totalWidth, double.PositiveInfinity));
height = Math.Max(height, child.DesiredSize.Height);
}
}
}
}
#endregion
【问题讨论】:
-
@Clemens,我发现了一个类似的问题并附上了代码。有什么想法吗?
标签: wpf custom-controls wrappanel measureoverride