Window.Loaded和Window.ContentRendered事件之间的区别是什么

时间:2013-08-26 20:47:30

标签: wpf events window

WPF中的Window.LoadedWindow.ContentRendered事件之间有什么区别? ContentRendered事件被称为第一个?

Window.ContentRendered事件here的说明只是说

  

在渲染窗口内容后发生。

Window.Loaded事件here的说明

  

在布置,渲染和准备交互元素时发生。

我有一个案例,我想将窗口的MaxHeight设置为显示我的窗口的屏幕的工作区域的高度。我应该在哪个事件中进行?

编辑:

我想我找到了我想要的东西,但现在我更加困惑了。首先发生Loaded事件,然后发生ContentRendered事件。在Chris Sells编写的WPF编程一书中Ian Griffiths,它说Loaded事件是

  

在显示窗口之前升起

'ContentRendered`事件是

  

在视觉上呈现窗口内容时触发。

这与MSDN文档中关于Loaded事件的说法相矛盾:

  

在布置,渲染和准备交互元素时发生。

现在更令人困惑。

4 个答案:

答案 0 :(得分:52)

我认为两个事件之间几乎没有什么区别。为了理解这一点,我创建了一个简单的操作示例:

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

至于StylesTemplates,在此阶段它们已成功应用,在这些事件中我们将能够访问它们。

例如,我们要添加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

答案 1 :(得分:42)

如果您访问此链接https://msdn.microsoft.com/library/ms748948%28v=vs.100%29.aspx#Window_Lifetime_Events并向下滚动至Window Lifetime Events,它将显示活动订单。

打开:

  1. SourceInitiated
  2. 激活
  3. 加载
  4. ContentRendered
  5. 关闭:

    1. 停用

答案 2 :(得分:10)

如果您正在使用数据绑定,则需要使用ContentRendered事件。

对于下面的代码,引发Loaded事件时Header为NULL。 但是,当引发ContentRendered事件时,Header会获取其值。

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

答案 3 :(得分:-2)

这与Window.ContentRenderedWindow.Loaded之间的区别无关,而与Window.Loaded事件的使用方式有关:

我用它来避免所有需要很长时间才能启动的应用程序中的启动画面。

    // initializing my main window
    public MyAppMainWindow()
    {
        InitializeComponent();

        // Set the event
        this.ContentRendered += MyAppMainWindow_ContentRendered;
    }

    private void MyAppMainWindow_ContentRendered(object sender, EventArgs e)
    {
        // ... comes up quick when the controls are loaded and rendered

        // unset the event
        this.ContentRendered -= MyAppMainWindow_ContentRendered;

        // ... make the time comsuming init stuff here
    }