Home > WPF > Loaded event of a WPF control may be fired repeatedly

Loaded event of a WPF control may be fired repeatedly

January 21st, 2008

In all my Windows Forms applications, I usually start with a common base class for forms and controls that provides a bunch of convenience properties, subscribes to common events, handles proper cleanup etc. I also implement an empty virtual InitControl method which can be overridden by deriving controls to initialize themselves.

As you can see in the Windows Forms snippet below, InitControl is being called right after the control’s Load event has been fired:

/// <summary>
/// Inits the base class and registers event listeners.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{     
  base.OnLoad(e);
  
  if (!DesignMode)
  {
    InitControlInternal();       
    InitControl();
    initControlCompleted = true;
  }
}


/// <summary>
/// An empty template method which is being invoked after the
/// control has been loaded during <see cref="OnLoad"/>.
/// </summary>
/// <remarks>The base class does not invoke this method if
/// the control is in design mode.</remarks>
protected virtual void InitControl()
{
  //this method is supposed to be overridden. Initialization of
  //the base class itself happens in InitControlInternal
}

 

Naturally, I kept this practice in WPF using the Loaded event which is available for all WPF controls. But to my surprise, InitControl method was getting called repeatedly while I expected it to be called just once, which causes some controls to be re-initialized over and over again. The reason in my case was a TabControl that hosted my user controls. As it turned out, TabControl unloads/reloads user controls with every tab switch.

Unfortunately, there seems to be no common solution to this very problem – you will have to decide how to handle Loaded events specifically for your initialization logic. However:

  • Using Loaded may not be problem in a lot of scenarios, but keep in mind that you might run in trouble when depending on it, especially with a reusable control.
  • You can use the Initialized event of a control rather than Loaded. Check the API documentation for a description of the two events.
  • Use a boolean field to track whether your initialization code has alreay been invoked:

    protected override void InitControl()
    {
      if (initControlCalled) return;
    
      initControlCalled = true;
      //init control
      ...
    }

 

I’ve implemented a short sample that demonstrates the issue. Basically, it’s a tab control that hosts a user control on one of its tab items:

<TabControl>
  <TabItem Header="Tab 1">
    <!-- the user control that counts Loaded events -->
    <local:LoadedCounter />
  </TabItem>

  <TabItem Header="Tab 2">
    <TextBlock>Switch back to trigger event in tab 1.</TextBlock>
  </TabItem>
</TabControl>

 

Once you switch back and forth, you can see that Loaded is being invoked with every switch:

TabControl

Download Sample Project (VS2008)


Author: Categories: WPF Tags: ,
  1. February 6th, 2008 at 18:41 | #1

    Tracking the Unloaded event can help, though we’ve found that you can still get multiple Loaded events before you get an Unloaded event. Pretty confusing. Using the Boolean field is probably the best solution.

  2. herbert
    August 4th, 2008 at 04:12 | #2

    Hi,
    I meet the same problem, and I think it was because that the Tabcontrol will remove the content of current TabItem from the visual tree and add the content of the selected TabItem to the visual tree when you switch Tabs. Then as the visual tree updated, there will be loaded and unloaded event fired for the newly added control and removed control respectively.
    I solved this problem by write a new tab control, which added all the items to the visual tree at the very beginning, and just make it hiden when the item was unselected, make it visible when the item was selected. This accelerate the switch speed a lot, especialy when the TabItem’s content is complex.

  3. andre
    September 3rd, 2008 at 14:38 | #3

    herbert, but what is about loaded content in tabs of TabControl if you didn’t click on them. They won’t be loaded. Your approach don’t work.

  4. Aleck
    July 9th, 2009 at 19:24 | #4

    Can you share a solution where you got multiple Loaded events?

  1. April 28th, 2009 at 17:22 | #1
  2. January 1st, 2010 at 05:29 | #2