What's the difference between the Window.Loaded and Window.ContentRendered events

Solution 1:

I think there is little difference between the two events. To understand this, I created a simple example to manipulation:

XAML

<Window x:Class="LoadedAndContentRendered.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Name="MyWindow"
        Title="MainWindow" Height="1000" Width="525"
        WindowStartupLocation="CenterScreen"
        ContentRendered="Window_ContentRendered"     
        Loaded="Window_Loaded">

    <Grid Name="RootGrid">        
    </Grid>
</Window>

Code behind

private void Window_ContentRendered(object sender, EventArgs e)
{
    MessageBox.Show("ContentRendered");
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Loaded");
}   

In this case the message Loaded appears the first after the message ContentRendered. This confirms the information in the documentation.

In general, in WPF the Loaded event fires if the element:

is laid out, rendered, and ready for interaction.

Since in WPF the Window is the same element, but it should be generally content that is arranged in a root panel (for example: Grid). Therefore, to monitor the content of the Window and created an ContentRendered event. Remarks from MSDN:

If the window has no content, this event is not raised.

That is, if we create a Window:

<Window x:Class="LoadedAndContentRendered.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Name="MyWindow"        
    ContentRendered="Window_ContentRendered" 
    Loaded="Window_Loaded" />

It will only works Loaded event.

With regard to access to the elements in the Window, they work the same way. Let's create a Label in the main Grid of Window. In both cases we have successfully received access to Width:

private void Window_ContentRendered(object sender, EventArgs e)
{
    MessageBox.Show("ContentRendered: " + SampleLabel.Width.ToString());
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Loaded: " + SampleLabel.Width.ToString());
}   

As for the Styles and Templates, at this stage they are successfully applied, and in these events we will be able to access them.

For example, we want to add a Button:

private void Window_ContentRendered(object sender, EventArgs e)
{
    MessageBox.Show("ContentRendered: " + SampleLabel.Width.ToString());

    Button b1 = new Button();
    b1.Content = "ContentRendered Button";
    RootGrid.Children.Add(b1);
    b1.Height = 25;
    b1.Width = 200;
    b1.HorizontalAlignment = HorizontalAlignment.Right;
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Loaded: " + SampleLabel.Width.ToString());

    Button b1 = new Button();
    b1.Content = "Loaded Button";
    RootGrid.Children.Add(b1);
    b1.Height = 25;
    b1.Width = 200;
    b1.HorizontalAlignment = HorizontalAlignment.Left;
}

In the case of Loaded event, Button to add to Grid immediately at the appearance of the Window. In the case of ContentRendered event, Button to add to Grid after all its content will appear.

Therefore, if you want to add items or changes before load Window you must use the Loaded event. If you want to do the operations associated with the content of Window such as taking screenshots you will need to use an event ContentRendered.

Solution 2:

If you visit this link https://docs.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms748948(v=vs.100)#window-lifetime-events and scroll down to Window Lifetime Events it will show you the event order.

Open:

  1. SourceInitiated
  2. Activated
  3. Loaded
  4. ContentRendered

Close:

  1. Closing
  2. Deactivated
  3. Closed

Solution 3:

If you're using data binding, then you need to use the ContentRendered event.

For the code below, the Header is NULL when the Loaded event is raised. However, Header gets its value when the ContentRendered event is raised.

<MenuItem Header="{Binding NewGame_Name}" Command="{Binding NewGameCommand}" />