Подтвердить что ты не робот

Какая разница между событиями Window.Loaded и Window.ContentRendered

Какая разница между событиями Window.Loaded и Window.ContentRendered в WPF? Вызывается ли событие ContentRendered первым?

Описание события Window.ContentRendered здесь просто говорит

Происходит после визуализации содержимого окна.

Описание события Window.Loaded здесь говорит

Происходит, когда элемент выложен, отображен и готов к взаимодействию.

У меня есть случай, когда я хочу установить окно MaxHeight на высоту рабочей области экрана, отображающего мое окно. Какое событие я должен сделать?

Edit:

Думаю, я нашел то, что искал, но теперь я еще больше смущен. Событие Loaded происходит сначала, а затем происходит событие ContentRendered. В книге "Программирование WPF" Криса Селлса и Иана Гриффитса говорится, что событие Loaded

Поднято перед отображением окна

Пока событие ContentRendered

Поднимается, когда визуальное отображение содержимого окна.

Это противоречит тому, что в документации MSDN говорится о событии Loaded:

Происходит, когда элемент выложен, отображен и готов к взаимодействию.

Это еще более запутанно.

4b9b3361

Ответ 1

Я думаю, что между этими двумя событиями мало различий. Чтобы понять это, я создал простой пример манипуляции:

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");
}   

В этом случае сообщение Loaded появляется первым после сообщения ContentRendered. Это подтверждает информацию в документации.

В общем случае в WPF событие Loaded срабатывает, если элемент:

размещается, отображается и готово к взаимодействию.

Так как в WPF Window является одним и тем же элементом, но он должен быть, как правило, содержимым, расположенным на панели корня (например: Grid). Поэтому для контроля содержимого Window и создания события ContentRendered. Замечания из MSDN:

Если в окне нет содержимого, это событие не будет создано.

То есть, если мы создадим 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" />

Он будет работать только с событием Loaded.

Что касается доступа к элементам в Window, они работают одинаково. Позвольте создать Label в главном Grid Window. В обоих случаях мы успешно получили доступ к 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());
}   

Что касается Styles и Templates, на этом этапе они успешно применяются, и в этих случаях мы сможем получить к ним доступ.

Например, мы хотим добавить 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;
}

В случае события Loaded Button добавить к Grid сразу при появлении Window. В случае события ContentRendered Button добавить к Grid после того, как появится его содержимое.

Поэтому, если вы хотите добавить элементы или изменения до загрузки Window, вы должны использовать событие Loaded. Если вы хотите выполнять операции, связанные с содержимым Window, например, с помощью скриншотов, вам нужно будет использовать событие ContentRendered.

Ответ 3

Если вы используете привязку данных, вам нужно использовать событие ContentRendered.

Для приведенного ниже кода заголовок имеет значение NULL, когда событие Loaded поднято. Тем не менее, заголовок получает свое значение, когда событие ContentRendered создается.

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