一个WPF用户控件的Loaded事件会触发多次

43

要在 WPF 中实现基于选项卡的环境,我们需要将表单转换为用户控件,但是这样做时,用户控件的 Loaded 事件会被调用两次

在搜索互联网时,其他人也指出了这个问题。我们如何确保只调用一次加载事件?因为当它被多次调用时,我们控件的初始化会发生多次。


我尝试在一个空的.NET 4.0 WPF应用程序中重现这个问题,发现Loaded事件只触发了一次。您是否尝试查看调用堆栈,以查看在触发Loaded事件之前.NET Framework中是否发生了奇怪的事情? - Bob Wintemberg
2
将您的用户控件放置在选项卡控件内,这样当切换选项卡时,您就可以重现该问题。 - Eternal21
尝试使用页面和框架。对于控件分组来说,这样做更简单、更清晰。 - Justanother Okie
4个回答

51

如同这篇博客所解释的那样,当一个控件即将被呈现(例如添加到可视化树)时,Loaded事件就会触发。

有几个控件可能会导致你的控件多次加载/卸载。例如,原生WPF TabControl只会呈现选定选项卡的内容。因此,当您选择新选项卡时,之前选定选项卡的内容会被卸载。如果你返回到之前选定的选项卡,则它的内容会重新加载。

一种解决方法是使用布尔型变量来标记您是否已经初始化了控件,正如其他人建议的一样。或者,您也可以尝试使用Initialized事件。


2
我正在使用TabControl的“ItemsSource”来绑定多个选项卡,并使用“DataTemplate”将ViewModel绑定到选项卡视图。在我的情况下,不仅会再次触发“Loaded”事件,而且选项卡视图的构造函数也会再次调用。似乎每次切换选项卡时,WPF都会完全重新创建我的选项卡控件。 - Felix
@Felix 我也遇到了同样的问题,有解决方案吗? - Luke
@Luke 这是一个我们无法改变的问题。所以我把所有东西都保存在 ViewModel 中,让 WPF 每次重新创建它。 - Felix

27

你的路由事件处理程序应该在第一时间从Loaded钩子中移除自己。

public class MyClass : Window
{
    public MyClass()
    {
        Loaded += MyLoadedRoutedEventHandler;
    }

    void MyLoadedRoutedEventHandler(Object sender, RoutedEventArgs e)
    {
        Loaded -= MyLoadedRoutedEventHandler;
        /// ...
    }
};

嗯...你的建议确实救了我的狗命,Glenn...但是你能解释一下为什么这个移除应该在事件处理程序内部进行吗?谢谢。 - Richard Hammond
6
@RichardHammond 因为,除了这个时间点,你还有什么机会确信事件已经成功触发了呢?你会建议将移除放在哪里?请注意,翻译时不得添加解释或其他非翻译内容。 - Glenn Slayden

3

在事件中设置一个loaded标志,如果该标志已经被设置,则不执行任何操作。


感谢您的建议,这是一个真正的问题吗?由于选项卡的原因,加载事件被调用了两次。 - Muhammad Akhtar

0

如上所述,您可以使用布尔标志进行操作。

bool isPageLoadingForFirstTime = true;

public void LoadedEvent()
{
  if(ispageLoadingForFirstTime)
   {
      //do something
      ispageLoadingForFirstTime = false;
   }
}


你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接