好的,我回答这个问题是为了向人们展示为什么 CodeNaked 的答案是正确的,但如果你愿意,可以加上星号,并提供一种解决方法。但是在良好的 SO-citizenship 中,我仍然将他标记为已回答,因为他的回答将我带到了这里。
更新:我已将接受的答案移至此处,原因有两个。一,我想让人们知道有一个解决方案(大多数人只阅读接受的答案并继续前进),二,考虑到他有 25K 的代表,我认为他不会介意我收回它!:)
这就是我所做的。为了测试这一点,我创建了这个子类......
public class TestPanel : DockPanel
{
protected override Size MeasureOverride(Size constraint)
{
System.Console.WriteLine("MeasureOverride called for " + this.Name + ".");
return base.MeasureOverride(constraint);
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
System.Console.WriteLine("ArrangeOverride called for " + this.Name + ".");
return base.ArrangeOverride(arrangeSize);
}
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
System.Console.WriteLine("OnRender called for " + this.Name + ".");
base.OnRender(dc);
}
}
...我这样布置(注意它们是嵌套的):
<l:TestPanel x:Name="MainTestPanel" Background="Yellow">
<Button Content="Test" Click="Button_Click" DockPanel.Dock="Top" HorizontalAlignment="Left" />
<l:TestPanel x:Name="InnerPanel" Background="Red" Margin="16" />
</l:TestPanel>
当我调整窗口大小时,我得到了这个......
MeasureOverride called for MainTestPanel.
MeasureOverride called for InnerPanel.
ArrangeOverride called for MainTestPanel.
ArrangeOverride called for InnerPanel.
OnRender called for InnerPanel.
OnRender called for MainTestPanel.
但是当我调用InvalidateVisual
'MainTestPanel'(在按钮的'Click'事件中)时,我得到了这个......
ArrangeOverride called for MainTestPanel.
OnRender called for MainTestPanel.
注意没有调用任何测量覆盖,只调用了外部控件的 ArrangeOverride。
这并不完美,好像您ArrangeOverride
的子类中有一个非常繁重的计算(不幸的是我们这样做)仍然会被(重新)执行,但至少孩子们不会落入同样的命运。
但是,如果您知道没有一个子控件具有设置了 AffectsParentArrange 位的属性(同样,我们这样做了),您可以更好地使用 NullableSize
作为标志来禁止重新输入 ArrangeOverride 逻辑,除非需要时,像这样...
public class TestPanel : DockPanel
{
Size? arrangeResult;
protected override Size MeasureOverride(Size constraint)
{
arrangeResult = null;
System.Console.WriteLine("MeasureOverride called for " + this.Name + ".");
return base.MeasureOverride(constraint);
}
protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize)
{
if(!arrangeResult.HasValue)
{
System.Console.WriteLine("ArrangeOverride called for " + this.Name + ".");
// Do your arrange work here
arrangeResult = base.ArrangeOverride(arrangeSize);
}
return arrangeResult.Value;
}
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
System.Console.WriteLine("OnRender called for " + this.Name + ".");
base.OnRender(dc);
}
}
现在,除非有什么特别需要重新执行排列逻辑(就像调用 MeasureOverride 那样),否则您只会获得 OnRender,如果您想显式强制排列逻辑,只需将大小清零,调用 InvalidateVisual 和 Bob 是你的叔叔!:)
希望这可以帮助!