2

I have a custom control that needs to be informed of layout changes from the parent. So if the parent relayouts the child, i want to calculate the new visual position. Unfortunately ArrangeOverride on the child won't get called, which makes sense, because the position doesn't really change inside the child control. Now in the layout pass, my custom control gets properly positioned but the ArrangeOverride is not called. To give you a clearer picture of what i'm trying to achieve: I have a control, that blurs the background giving an aero glass like effect. To achieve that, my control renders a background control into a visual brush and calculates the viewbox for that brush to make the background shine through, which then is blurred via a blur effect. Its working perfectly fine, as long as the layout doesn't change. If it does, i need to update the brush. And i did this inside the ArrangeOverride method.

So i tried to use ArrangeOverride, MeasureOverride, various combinations of Invalidating or Parent invalidating. At first i inherited from ContentControl but changed that to Decorator, thinking that the Decorator might have some special behavior to no use. I want to avoid LayoutChanged as much as possible because its a very very evil event. I would give you some code, but there is nothing special about it and i think its a rather fundamental problem not really bound to my code. The layouter by the way can be anything(not only canvas). So what event, methods or ways do i have to get informed of the parent telling my control "I know you didn't changed anything, but i did repositioned you".

Community
  • 1
  • 1
dowhilefor
  • 10,971
  • 3
  • 28
  • 45
  • Not sure, but will this help you? - the dock panel with last child fill – Learner Jul 23 '12 at 11:56
  • Have you tried the [LayoutUpdated](http://msdn.microsoft.com/en-us/library/system.windows.uielement.layoutupdated) event on the child? – Clemens Jul 23 '12 at 12:15
  • @Clemens well yeah and its the very last option i want to take. Because like i wrote its a very evil event, that you should never use i still don't know why Microsoft kept it, or why they implemented it the way they did. To make it short, this event is fired when ANY control gets updated. So if you have an animation somewhere, or some mouse over effects, it gets called any time no matter where you registered this event. – dowhilefor Jul 23 '12 at 12:20
  • have a look at this.. http://stackoverflow.com/questions/7801680/how-can-i-manually-tell-an-owner-drawn-wpf-control-to-refresh – Learner Jul 23 '12 at 12:47
  • Just did a very basic test with a derived Shape on a Canvas. It shows that `ArrangeOverride` is called whenever the child position changes (by Canvas.Left/Top here). As far as i understood the arrange mechanics, every parent *must* call `Arrange` on all of its children, which results in a call to `ArrangeOverride` in each child. – Clemens Jul 23 '12 at 12:54
  • While its true that it must call Arrange, it might not trigger the call to ArrangeOverride. I'm pretty sure wpf uses the IsArrangeValid flag to check if a call to ArrangeOverride is really necessary and skips it otherwise. – dowhilefor Jul 23 '12 at 12:56
  • Well, i'm not so sure. Following your interpretation, why should a simple shape with unchanged size ever have IsArrangeValid == false after once being arranged? – Clemens Jul 23 '12 at 13:01
  • Good question. I'm not sure to be honest, its just what i though made the most sense, why the method was sometimes not called. Maybe its different depending on the Layouter you use. I experienced somethings like that in the past, when working on my own layouters, passing the same value to Arrange multiple times in a row, doesn't trigger that many ArrangeOverrides on the child, so there seems to be some kind of caching. – dowhilefor Jul 23 '12 at 13:13

1 Answers1

0

So i fixed it in a way i'm not very happy about, but it resolved alot of other unecessary stuff just to make it work, like when the blur control itself is animated. So this solution works now with whatever happens. While i avoided the LayoutUpdated event, i used a similar "evil" event. CompositionTarget.Rendering so in the Loaded event, i register to the rendering event, in the Unloaded i unregister from the rendering event. That way it doesn't matter how often Loaded or Unloaded gets called. In the rendering event itself i just trigger my VisualBrush.Viewbox invalidation code. This works perfectly fine, even if though the event is fired alot. I don't use the blur that much so it doesn't impact the performance so much ... for now.

dowhilefor
  • 10,971
  • 3
  • 28
  • 45
  • But `CompositionTarget.Rendering` is called far more often than `LayoutUpdated`, or to be more precise it is called on every frame, which typically means 60 times a second. When you talk about *evil*, this is really evil. – Clemens Jul 23 '12 at 13:38
  • @Clemens i totally i agree, i think its just stupid superstition on my side why i prefer it right now than layoutchanged. If you post your comment about LayoutUpdated event i mark it as the answer, because its not fair to not give it to you, just because i used another similar event. – dowhilefor Jul 23 '12 at 13:41
  • Having the answer or not is not the point. I simply believe that you should continue to find out why your `ArrangeOverride` doesn't get called. There must be a reason. I also greatly dislike `LayoutUpdated`, so i won't write that as an answer. – Clemens Jul 23 '12 at 13:45
  • 1
    I agree, but my Boss and my deadline unfortunately tells me otherwise ;). But i'm not the kind a guy to leave it like that ... i will check it later, and of course i will update this thread here to keep everyone posted. – dowhilefor Jul 23 '12 at 13:47