John Reynolds
John Reynolds

Reputation: 5057

What event is fired when a UserControl is displayed?

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

Answers (6)

Riva
Riva

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

Mustafa Ekici
Mustafa Ekici

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

Ievgen
Ievgen

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

Mirza Bilal
Mirza Bilal

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

Rick Sladkey
Rick Sladkey

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

brunnerh
brunnerh

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

Related Questions