WPF - LayoutUpdated事件反复触发

13

我正在为我的WPF应用程序添加一些动画效果。

感谢Dan Crevier的独特解决方案,可以对面板子元素进行动画处理,再加上WPF Penner动画库,使得我的控件看起来很棒,并且它的子元素可以通过流畅的动画移动。

不幸的是,这一切都带来了性能开销。当添加/删除项或调整控件大小时,我很高兴承受性能损失,但似乎这种性能损失会在应用程序的整个生命周期中持续存在,即使项目是完全静态的。

PanelLayoutAnimator类使用附加属性将UIElement.LayoutUpdated事件挂钩。当事件触发时,渲染变换会被动画处理,使得子元素可以平滑地滑动到新位置。

不幸的是,即使在应用程序闲置时(至少我认为代码没有执行任何操作 - 应用程序没有焦点,鼠标是静止的),LayoutUpdated事件似乎每秒钟就会触发一次。由于事件处理程序无法立即确定事件的原因,因此必须重新评估控件的所有子元素。这个事件在闲置时大约每秒钟被调用一次。当实际使用应用程序时,频率会增加。

那么我的问题是,我如何提高性能? 任何有助于解决问题的答案都将不胜感激,但我目前卡在以下子问题上:

  1. 是什么导致LayoutUpdated事件频繁触发?这是否应该发生?如果不应该,我如何找出为什么会发生并阻止它?

  2. 在处理程序内部是否有更方便的方法可以知道是否发生了可能会移动子元素的事件? 如果是这样,我可以早早退出并避免循环每个子元素所带来的开销。

  3. 目前,当面板中有超过N个子元素时,我将通过禁用动画来解决此问题。


Drew,请问你能否分享一小段代码示例,以便重现问题? - Anvaka
是的,因为 LayoutUpdated 应该只在实际上导致布局更新的情况下才会触发...尽管听起来很明显。 :) 因为您没有与窗口进行交互,所以我不知道除了尺寸、位置或布局变换的动画之外,还有什么会触发这种情况。 - Drew Marsh
2
这个应用程序相当大。如果LayoutUpdated不应该经常触发,那么我可以使用什么技术来找出它为什么会触发呢? - Drew Noakes
我还想指出,我在一个窗体中使用了WinForms的ElementHost - Drew Noakes
2
这篇文章清晰地解释了问题并提供了更好的解决方案:-> https://blogs.msdn.microsoft.com/devdave/2008/05/27/layout-events-sizechanged-and-layoutupdated/ - deathrace
1个回答

13

如果你在附加到 LayoutUpdated 事件的 EventHandler 中更新 UI,那么这也将触发该事件!

例如:

void my_LayoutUpdatedEvent(object sender, EventArgs e)
{
    textBlock1.Text = "changed";
    Console.Out.WriteLine("text changed!");
}
    

代码将进入无限循环更新。

也许你需要像这样做:

void my_BetterLayoutUpdatedEvent(object sender, EventArgs e)
{
    if (!hasChanged)
        textBlock1.Text = "changed";
    hasChanged = true;
    Console.Out.WriteLine("text changed!");
}

2
有趣的观点,很有道理。我已经不再从事那个应用程序的工作了,但这听起来是可行的。希望能对其他人有所帮助。 - Drew Noakes
1
有没有可能检查是哪个UI更新导致了无效? - simo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接