所以我在对象的加载事件中注册了一些事件处理程序。
tv.PreviewMouseDown += new MouseButtonEventHandler(SignalScrollViewer_PreviewMouseDown);
但我有两个问题。
- 如果加载发生两次并尝试再次添加事件处理程序会出现问题吗?
- 我应该如何处理取消注册事件?它会在销毁时自动处理注销,还是我需要在某些事件(如卸载或其他情况下)处理它?
是的,这将导致另一个订阅导致处理程序执行两次。您可以在已加载的处理程序中删除已加载的处理程序。
MSDN:
由于用户启动的系统主题更改,可能会在控件上同时引发 Loaded 和 Unloaded。主题更改会导致控件模板和包含的可视化树失效,进而导致整个控件卸载和重新加载。因此,不能假定仅在通过导航到页面首次加载页面时才发生 Loaded。
如果加载发生两次并尝试再次添加事件处理程序会出现问题吗?
该事件将被多次订阅。您可能想要处理这种情况。
我应该如何处理取消注册事件?它会在销毁时自动处理注销,还是我需要在某些事件(如卸载或其他情况下)处理它?
您可以在 Unloaded 或类似中取消注册它。通常,您只需要在您订阅的事件的对象超出您的生命周期时才需要执行此操作。如果它是您自己内部的对象(即:从用户控件订阅用户控件内按钮上的事件),则不需要取消订阅。
通常从构造函数内部订阅事件,即在tv
对象被创建后立即订阅。如果你把它们放在一起,就不可能多次订阅同一个tv
对象。
有人会希望在 Loaded 中注册事件处理程序并在 Unloaded 中删除它们,因此处理事件的任何对象都将具有定义的生命周期。因此,人们会希望每个 Loaded 事件在控件显示时仅发生一次,并且在控件从视线中移除时紧随其后的是 Unloaded 事件。
但是,Loaded 可能会引发多次,具体取决于您的布局: Expander 导致 Loaded 被引发两次,但在 Expander 内的控件上仅卸载一次,并且 TabControl 可能会为不同的 TabItems(不同的数据)重用相同的控件而不引发 Loaded 或中间卸货。
我找到了解决这个问题的两种方法:要么使用 DataTemplates(这至少在 TabControl 案例中有所帮助),要么使用 DataContextChanged 事件来注册/取消注册事件,这是确保接收事件的对象是始终是当前的 DataContext(即 ViewModel)。
您可能还想查看以下链接以获取有关附加和删除事件处理程序和其他行为的更多信息:http ://wpfglue.wordpress.com/2009/12/11/the-sticky-component-framework/