Reputation: 5057
I'm trying to add a fade effect (animation) for WPF UserControls
(although rather for FrameworkElement
, to make it more general).
If I let the Loaded
event trigger the initial fade-in, the fade animation will sometimes have started before the UserControl has been displayed. The result is a mess. That happens for example if the UserControl does something lengthy (a few tenths of a second), like execute a query, in the Loaded event handler.
So, I would need to handle some event that FrameworkElement/UserControl gets when the content has been rendered, and start the fade-in then. The System.Windows.Window
has a ContentRendered
event, but UserControl has not. So, what event is fired when a FrameworkElement (or UserControl) has been rendered?
Upvotes: 44
Views: 49987
Reputation: 695
Years late, but since I was looking for working solution since now in vain, I want to share my discovery.
If you want a ContentRendered
event for any Control (or any Visual or even DependencyObject), you have to dig down to Visual
.
I use this code:
// Wait for Control to Load
void TestUserControl_Loaded(object sender, RoutedEventArgs e)
{
// Get PresentationSource
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);
// Subscribe to PresentationSource's ContentRendered event
presentationSource.ContentRendered += TestUserControl_ContentRendered;
}
void TestUserControl_ContentRendered(object sender, EventArgs e)
{
// Don't forget to unsubscribe from the event
((PresentationSource)sender).ContentRendered -= TestUserControl_ContentRendered;
// ..
}
You have to wait for Control Loaded
otherwise PresentationSource.FromVisual() returns null.
Various Dispatcher.BeginInvoke methods didn't work consistently for me. Sometimes firing my rendered event long before the control was actually displayed.
This does work for me every time.
I am aware that I am playing with HwndSource here, which is quite low level and I'm not sure of possible implications. (Maybe somebody more experienced can elaborate.)
Upvotes: 21
Reputation: 7470
You can use GotFocus Event
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding ContentControlLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Upvotes: 3
Reputation: 4443
Try to check size on SizeChanged or LayoutUpdated. Do job when actual width or height not equals to 0.
view.LayoutUpdated+=(o,e)=>
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// You can also unsubscribe event here.
loaded =true;
}
}
Upvotes: 30
Reputation: 1050
You can use IsVisibleChnaged event Assign event handler
MyUserControl.IsVisibleChanged += ScheduleUserControl_IsVisibleChanged;
In event handler check for if is visible or not.
void _IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
//Visible
}
else
{
//Not Visible
}
}
Upvotes: 10
Reputation: 34240
You can schedule the beginning of your Storyboard
with a lower priority, for example:
Dispatcher.BeginInvoke(BeginStoryboardAction, DispatcherPriority.ContextIdle);
Here's an article that discusses the issues related to using this method:
Upvotes: 8
Reputation: 184476
Maybe try IsVisibleChanged
, haven't used it much myself though.
This event is not raised if the element is not being rendered by the layout system, for reasons other than the value of the IsVisible property. For example, the element might not have an associated visual.
Upvotes: 7