好的,我回答这个问题是为了向人们展示为什么 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 是你的叔叔!:)
希望这可以帮助!