2

Say I have a Canvas containing a child Rectangle. The user then resizes the Rectangle by pulling the top left corner upwards and to the left (leaving the bottom right corner anchored).

The new position and size of the Rectangle is set like so (quasi code):

Canvas.SetLeft(rectangle, newLeft);
Canvas.SetTop(rectangle, newTop);
rectangle.Width += oldLeft - newLeft;
rectangle.Height += oldTop - newTop;

Will WPF perform a redraw for each of these changes in positioning/size (i.e. will each property change invalidate the elements involved and trigger a redraw by itself) or will they be "queued" ("marked as dirty") and performed all at once at some "next redraw" (whenever that may be)?

Edit: I am curious about to what degree (if any) setting Canvas.Left and Canvas.Top separately represents redundant / inefficient code, due to the multiple InvalidateArrange calls done by Canvas in such a scenario (compared to what, say, unified Canvas.SetTopLeft or Canvas.SetRect methods would). This partly due to warnings in the MSDN documentation that "Frequent calls to InvalidateArrange or in particular to UpdateLayout have significant performance consequences."

d7samurai
  • 3,086
  • 2
  • 30
  • 43

1 Answers1

1

In general, a basic WPF application will have one thread. This means that it can do one thing at a time, which also means that it cannot render the UI when it is reading the instructions from your code. So, after it has read all of the instructions from your code and program execution has reached the end of the current method, then it will go into render mode to render the UI in one pass.

This is why the UI 'hangs' when program execution is processing some long running task that has not been run using a background thread (I'm not talking about your code here). The UI will be unresponsive until the current method has ended and program execution can return to the UI.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • OK. But even with one thread, the UI _could_ be doing a redraw at each property change - due to the fact that changing a (dependency) property sends a notification of that change to whoever listens - which could include the rendering system. I.e. changing the Width property of an element raises an event that would/could be consumed somewhere - before the next instruction in _my_ code is executed. If that somewhere handles screen redraws, it would happen, not _when_ (as in simultaneously) but _in between_ reading the instructions from my code. Hence the question. – d7samurai Nov 14 '13 at 13:36
  • And this could be the case regardless of whether "UI hang" is observed because the redraw could be occurring in a measure/arrange/redraw kind of pass behind the scenes even if the physical _screen_ isn't being re-rendered for it to visibly change until some later point in time (i.e. when the thread is freed up again to do so). – d7samurai Nov 14 '13 at 13:42
  • The UI will *not* update in between instructions regardless of any events or property change notification. It just doesn't work like that. – Sheridan Nov 14 '13 at 13:48
  • The reason I'm "concerned" is that the source code of `Canvas` shows that a change of Canvas.Left or Canvas.Top both calls InvalidateArrange on the element in question - i.e. InvalidateArrange is called twice when Left and Top are set (rather than once after they are both set). According to MSDN, "Frequent calls to InvalidateArrange or in particular to UpdateLayout have significant performance consequences". Not sure what happens when DependencyProperties like Width and Height are changed in this respect. – d7samurai Nov 14 '13 at 14:02
  • @d7samurai That's why WPF has this concept of a [`Dispatcher`](http://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx) to handle the priorities of the tasks performed by the UI thread. "rendering" occurs in `DispatcherPriority.Render`. – Federico Berasategui Nov 14 '13 at 14:14
  • @d7samurai The MSDN documentation of InvalidateArrange also says that *After the invalidation, the element will have its layout updated, which will occur asynchronously unless subsequently forced by UpdateLayout*. To my understanding this means that a second call to InvalidateArrange would only invalidate an already invalid layout, and would hence not create any additional load. – Clemens Nov 14 '13 at 14:19
  • @Clemens Yes, that makes sense. Except if it doesn't create any additional load, why does frequent calls to `InvalidateArrange` have "significant performance consequences", as they emphasize throughout the MSDN documentation..? – d7samurai Nov 14 '13 at 14:26
  • @d7samurai I guess what they mean is "don't call this frequently from your application code", as each time you call it on a UI element, the element's layout (or at least the arrange part of it) is invalidated and needs to be redone. – Clemens Nov 14 '13 at 14:29
  • @Clemens Well, setting Canvas.Left and then Canvas.Top is precisely equivalent to calling element.InvalidateArrange twice in succession (only with some _additional overhead_) - which is twice as frequent as doing it once. I was concerned about what happens next in that chain of events (no pun intended) since MS makes such a point of giving this performance warning. – d7samurai Nov 14 '13 at 14:33
  • @d7samurai But as long as both properties are set within the same Dispatcher operation (as they are here) there will be no intermediate layout update and hence no significant additional load. Only if you call InvalidateArrange frequently in separate dispatcher operations (e.g. frequent event handler calls), it will impact performance. – Clemens Nov 14 '13 at 14:50