Event that fires after element is resized - silverlight

Here is a problem: after loading some visual elements, I need to change something knowing their new sizes. There is MeasureOverride method, but it is called before changing the size. Is there any method that is called after it?
P.S. I know that I can calculate new sizes having old ones, but new sizes aren't calculated simply. It would be much easier to just use such an event (if it exists).

Are you looking for the FrameworkElement.SizeChanged event?
MSDN's description:
Occurs when either the ActualHeight or the ActualWidth properties change value on a FrameworkElement.
EDIT:
This article has a good description of both the SizeChanged and LayoutUpdated events, including an overview of how the layout loop works.

Related

LayoutUpdated event has stopped firing. Handlers are in place, any ideas?

I have a control which allows the user to add and manipulate n graphical and text layers. The layers are each usercontrols that are added to the parent control's canvas. I use the parent control's LayoutUpdated event to refresh transform specific variables and other stuff. With no change to the handler method, the LayoutUpdate event stopped firing. I've obviously done something that caused it, but I haven't been tinkering with anything that can logically tie to this new problem. Any ideas are appreciated - thanks.
JUST TO CLARIFY: I'm not asking for a solution - just an anecdote of experience with something similar - That will probably be more helpful than you can imagine. Thanks
The cause, in this case, was a WPF UserControl (kid) defined in xaml at design time inside a canvas without any dependency property values set. The canvas is inside another usercontrol of different type (mom). At runtime, a mom is instantiated and her kid is sized, positioned, and made visible within the canvas of mom based on the runtime size of mom as well as calling arguments that denote whether or not kid is to be visible. This instance of kid is only sized and positioned if it is requested to be visible, if not, it is only hidden (not sized, not positioned).
The presence of this instantiated, but unsized and unpositioned element within the canvas of mom was causing the failure of layoutupdated events to fire. This situation effected not only the instance in question, but all other instances created at runtime in the project afterward. (NOTE - no exception was raised)
The solution appropriate for this circumstance was to explicitly size and place this element within the canvas - even if it is not needed. The layoutupdated events then fire as expected. I would love to provide a more profound and generalized answer, but perhaps wiser people can include their insight as well. Thanks

MeasureOverride not always called on children's property changes

I wrote a panel similar to the built-in StackPanel. I works almost fine except for a slight problem:
Changing layout properties on children do not always cause the panel's MeasureOverride and ArrangeOverride to be called. They are always called when a child's Visibility property changes, but not when the Width and Height properties change.
I haven't yet managed to reproduce this behavior in a sample small enough to be appropriate for being included in a question on StackOverflow: But since it works fine in the trivial sample I made, I know I must do something avoidable in my actual panel.
So my question: In which circumstances does an element not invalidate its parents measure when changing size-related properties?
I tag this wpf also (I used Silverlight) to have a broader audience - I suspect this will apply to both xaml implementations equally.
I figured what my mistake was and under which condition the panel's MeasureOverride is no longer called on certain changes for size-related properties.
My panel called Measure on children with the exact size the children should have, rather on the size of the panel.
A panel doesn't get it's MeasureOverride method called when children begin to desire more space than was told to them is available in the last Measure call - which makes sense.
Summary: The parameter for the Measure method you call on a child must denote the space the parent panel allots to all children, not just the one Measure is called on.
You must make sure you call the base methods MeasureOverride.
protected override Size MeasureOverride(Size availableSize)
{
// you must call this
var throwaway = base.MeasureOverride(availableSize);
// your code here
return yourNewSize;
}

OnRender not called after InvalidateVisual()

A custom WPF Control overrides OnRender. The method generates and displays a Path from custom data. The data provider is bound using a Dependency Property. The Dependency Property registers for an event when data changed. This event in turn calls InvalidateVisual().
However, after the InvalidateVisual() the OnRender is not always called.
We use the Prism Framework and the Region functionallity. The Control in question is embedded in such a Region, which is activated and deactivated. However, the Control's property "IsVisible" is true whenever the region is active. But still, when calling InvalidateVisual() the OnRender method is not called...
What could prevent the OnRender method from being called?
I just had this problem, too.
Context
I've got a load of controls based on the DynamicDataDisplay graph components inside a VirtualizingStackPanel (inside a ListBox).
When there are more controls that are visible at once, but not enough for the VirtualizingStackPanel to start re-using them when you scroll then I see this issue with the D3 AxisControl class. For some reason it does a lot of work in it's OnRender method, which it tries to trigger by calling InvalidateVisual when something changes.
In the problem case the problem controls call InvalidateVisual but they never get a call to MeasureOverride, ArrangeOverride or OnRender. Interestingly, most of the controls still work, in one particular problem case I get the last 3 out of a set of 11 failing to work properly. Notably those 3 (and only those 3) receive a call to MeasureOverride immediately before the data binding update that triggers the call to InvalidateVisual.
My Fix
In the end I managed to fix it by adding a call to InvalidateMeasure alongside the call to InvalidateVisual.
It's a horrible solution, but it's not a performance critical part of our application, so I seem to be getting away with it.
If the size of your control is staying the same, you should not be using InvalidateMeasure() or InvalidateVisual() because they trigger an expensive re-layout.
WPF is a retained drawing system. OnRender() might be better called AccumulateDrawingObjects(), because it doesn't actually draw. It accumulates a set of drawing objects which WPF uses to draw your UI whenever it wants. The magic thing is, if you put a DrawingGroup into the DrawingContext during OnRender(), you can actually efficiently update it after OnRender, anytime you like.
See my answer here for more details..
https://stackoverflow.com/a/44426783/519568
I just had this problem, too.
I had a scrollbar for a control which only figured out during OnRender() how much space is really needed to display all content, which could be bigger than the available display space and therefor needed a scrollbar. It could happen that OnRender() called some methods which ultimately changed the value of the scrollbar which was supposed to start OnRender() with InvalidateVisual().
However, OnRender() did not get called again after InvalidateVisual(). I guess the reason is that InvalidateVisual() sets some flags which tells WPF that the control needs to get drawn again, but once OnRender() finishes, that flag gets reset. Here some pseudo code how I expect it to happen:
//someCode:
control.InvalidateVisual()
//code of InvalidateVisual()
control.RedrawFlag = true;
//WPF some time later:
if (control.RedrawFlag){
control.OnRender()
//OnRender code
//do some stuff
//decide control needs to be redrawn
//however, RedrawFlag is alreday true!
//next line is not changing anything
control.RedrawFlag = true;
//WPF finished executing control.OnRender
control.RedrawFlag = false;
}
I didn't further investigate if WPF really works this way, but it would explain why OnRender() does not get called a second time.
Instead of wasting even more time, I changed how to calculate the total width of the control content can be and put this code outside of OnRender().

Get window size without degrading performance

My WPF program sometimes needs the size of the window. The simplest solution is to bind the ActualWith and ActualHight. But how is the performance when doing so? Is the Height and Width updated repeatedly each time I resize the window?
Is there any way to get the size only when I need it?
As always, when you are worried about performance: test.
Binding to the ActualHeight and ActualWidth might be not so bad because the Window might not change that much/many times.
The only (proper) way to connect the ViewModel to the View is by using a binding. If this is too costly you could add two extra properties to the Window/View that only update (using a resize event for instance) when this is relevant to you. You could then bind the ViewModel to those.
My bet is that your application contains other things that need more attention ;)

Dynamic animations, Commands and separation of concerns

Scenario: I have a (numeric) textbox, a button, and a label. When the button is clicked I'd like the label to "animate" to the numeric value in the textbox (like a spinning dial)
Given:
a) that animations in storyboards cannot have databindings (because they are not FrameworkElements)
b) the lack of triggers in Silverlight
What is the best, and with least coupling of the view model to the view's storyboard, way to update the target animation value and start the animation when the button is clicked?
Note: The scenario is conceptual, so don't concentrate on the specifics of 'animating' numbers or anything
If your goal is strictly to reduce the code-behind in the view I think that an attached behaviour on the Label would work for this. The attached behaviour on the label would expose the number to be animated to and when this number changes an animation (in code) would be run to animate from the old value to the new value.
One drawback is that your animation is now in code, unless you store a templated (just has fake values to start with) version of it in a resource file somewhere where you can load it as needed and replace the templated values.
This article from Josh Smith seems to be the authority on Attached Behaviours;
http://joshsmithonwpf.wordpress.com/2008/08/30/introduction-to-attached-behaviors/
I recently had to solve a similar problem in an MVVM application. My problem was that I needed to animate a container's height from zero to auto. Since Auto is a dynamic value I recognized that the animation (or storyboard) would need to be built (or manipulated) on demand. The solution that I put in place involved using view code-behind to update and fire the animation.
This isn't the most MVVM-friendly approach; however, animations in WPF can be tricky in XAML. Since this solution is really just a workaround for a XAML limitation it seems okay to tie the code directly to the view. Likewise, if the views were mocked then there would be no framework elements to animate, so it really wouldn't make sense to place this code on the VM side.
Does anybody have a better approach?

Resources