Something strange…
I saw something strange today, so I tried to isolate and reproduce the problem, and I think I have.
This is what I was trying to do:
- I’m writing a gate entry application for a gym. When a member swipes their badge, a popup appears in the bottom-right corner.
- The popup is green (if it’s a valid swipe) or red if not.
- Additionally, the popup may show any number of alerts (e.g. overdue fees, barcode not found, Happy Birthday!, etc…)
So to implement this, I figured I’d create a Window, place it in the bottom-right corner of the screen; create an EntryViewModel (perform rules and logic to work out the state of the ‘Entry’) and finally, use a TemplateSelector to decide how to present the Popup view…
One thing I wanted to do was slide the red ones over to the left side of the screen, and keep them there (the green ones automatically fade away after 2 or 3 seconds)
So I added an animation in the UserControl to grab the parent Window (using a FindAncestor RelativeSource) and decrease the ‘Left’ property down to 0 over 1/2 a second.
What I saw was only *one* of the animations worked… that is, if the window contained a ‘green’ user control, it would fade away, but if it was for a ‘red’ one, it wouldn’t slide off to the left…
Puzzled, I changed the green animation to slide (instead of fade), and still it worked, but still the red one didn’t…
Well this bothered me, so I added a TextBlock into the UserControl, setting the Text to the exact same Binding as the animation (to make sure the parent Window was being correctly derived), and guess what? The animation started working…
Huh? I figured something had gone a bit wrong, and changing the template and re-compiling had fixed it, so I commented out the TextBlock and tried again… bugger me if the animation didn’t stop working again…
I’ve attached a sample app that demonstrates the problem… If anyone can unravel this and let me know what I’ve done wrong, I would be much obliged.
In the meantime, I have a TextBlock in my UserControl with Visibility set to ‘Hidden’ and a bloody big comment next to it saying ‘do not remove this seemingly meaningless TextBlock – It makes the animation work!!’
Update:
WPF Disciple, Microsoft MVP and thoroughly bloody good bloke Paul Stovell enlightened me on this one… What was happening was, the UserControls were attempting to run an animation whose Target objects were the parent Window for the Control. To find the Window, I had ‘reached up and out of the Control’, like this:
<DoubleAnimationUsingKeyFrames
Storyboard.Target="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"
Storyboard.TargetProperty="Left">
<LinearDoubleKeyFrame KeyTime="0:0:2" Value="50.0" />
</DoubleAnimationUsingKeyFrames>
but the problem was that this animation was being run (and hence this Binding was being evaluated) before the UserControl had been added to the Visual tree, due the way the Loaded event fires…
The ‘green’ UserControl contained a TextBlock that binds to the name off the EventViewModel, and subsequently the UserControl loaded event is fired just that little bit later (after the Control is added to the Visual tree) – so the ‘green’ ones were working just fine…
As per his suggestion, I have created the animations directly in the parent window (thereby removing the FindAncestor Binding), and fired an event in the UserControl to let the parent know some animation needs to be run…
I’l leave the problematic code here for reference: To see the problem, comment out the TextBlock from any of the UserControls…
Download: