我有两个自定义控件,用于显示注释和签名集合。每个控件都有一个按钮,用于更改显示样式--显示整个集合或仅显示前4个元素。
当我将这些控件放在默认的WrapPanel中时,它们可以正常工作:根据用户的操作展开或折叠。在我自己定制的带有新WrapPanel函数的ArrangeOverride中,它们也可以正常工作。
现在,我需要WrapPanel和选项"LastChildFill“(我在这里找到了示例)和自定义"WrapDirection”(类似于FlowDirection)。WrapPanel中的第一个或最后一个元素必须填充所有剩余的空间,而不是元素的MinWidth。因此,我创建了带有自定义MeasureOverride和ArrangeOverride的第三个MeasureOverride。它可以按我的意愿工作,但当我更改控件显示样式时,控件中的集合会发生变化,但在更改窗口大小之前,MeasureOverride在我的WrapPanel中才会启动。
更新: 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发布于 2017-05-12 15:00:07
我在这里找到了解决方案:How does a container know when a child has called InvalidateArrange?
对我来说很管用。
public static void OnPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
UIElement panel= VisualTreeHelper.GetParent(source) as UIElement;
if(panel != null)
{
panel.InvalidateMeasure();
panel.InvalidateArrange();
}
}https://stackoverflow.com/questions/43916815
复制相似问题