13

I've been adding a bit of animation to my WPF application.

Thanks to Dan Crevier's unique solution to animating the children of a panel combined with the awesome WPF Penner animations it turned out to be fairly straightforward to make one of my controls look great and have its children move about with some nice animation.

Unfortunately this all comes with a performance overhead. I'm happy to have the performance hit when items are added/removed or the control is resized, but it seems that this perf hit occurs consistently throughout the application's lifetime, even when items are completely static.

The PanelLayoutAnimator class uses an attached property to hook the UIElement.LayoutUpdated event. When this event fires, render transforms are animated to cause the children to glide to their new positions.

Unfortunately it seems that the LayoutUpdated event fires every second or so, even when nothing is happening in the application (at least I don't think my code's doing anything -- the app doesn't have focus and the mouse is steady.) As the reason for the event is not immediately apparent to the event handler, all children of the control have to be reevaluated. This event is being called about once a second when idle. The frequency increases when actually using the app.

So my question is, how can I improve the performance here? Any answer that assists would be appreciated, but I'm currently stuck on these sub-questions:

  1. What causes the LayoutUpdated event to fire so frequently? Is this supposed to happen, and if not, how can I find out why it's firing and curtail it?

  2. Is there a more convenient way within the handler to know whether something has happened that might have moved children? If so, I could bail out early and avoid the overhead of looping each child.

For now I will work around this issue by disabling animation when there are more than N children in the panel.

Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
  • Drew, could you please share small code sample which could reproduce the problem? – Anvaka Oct 16 '09 at 14:14
  • Yeah, because LayoutUpdated should really only be firing if something is actually causing the layout to update... obvious as that sounds. :) Since you're not interacting with the Window I don't know what would trigger this other than animations to dimensions, position or layout transform. – Drew Marsh Oct 16 '09 at 14:41
  • 2
    Hmm the app is fairly large. If LayoutUpdated shouldn't be firing regularly, then what technique can I use to find out why it is firing? – Drew Noakes Oct 16 '09 at 16:24
  • I might also point out that I'm using a WinForms `ElementHost` in a form. – Drew Noakes Oct 16 '09 at 16:25
  • 2
    This one clears the reason and gives better solution: -> https://blogs.msdn.microsoft.com/devdave/2008/05/27/layout-events-sizechanged-and-layoutupdated/ – deathrace Nov 24 '16 at 08:50

1 Answers1

13

If you're updating the UI from the EventHandler you attached to the LayoutUpdated event, this will also trigger that event!

For example:

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

will go into an infinite loop of updates.

Perhaps you need to do something like this:

void my_BetterLayoutUpdatedEvent(object sender, EventArgs e)
{
    if (!hasChanged)
        textBlock1.Text = "changed";
    hasChanged = true;
    Console.Out.WriteLine("text changed!");
}
Eliahu Aaron
  • 4,103
  • 5
  • 27
  • 37
Chris
  • 146
  • 2
  • 3
  • 2
    Interesting point, and it makes sense. I'm no longer working on that application, but this sounds plausible. Hopefully it helps someone else out. – Drew Noakes Jul 16 '12 at 22:07
  • 1
    Is it possible to check which UI was updating causing the invalidation? – simo Mar 13 '13 at 12:10