2009-02-02 78 views
99

我创建了一个定制的WPF用户控件,该控件旨在供第三方使用。我的控件有一个私人成员,它是一次性的,我想确保它的dispose方法将在包含窗口/应用程序关闭后始终被调用。但是,UserControl不是一次性的。我尝试实现IDisposable接口并订阅Unloaded事件,但在主机应用程序关闭时不会调用。如果可能的话,我不希望依赖于我的控件的消费者记住调用特定的Dispose方法。处置WPF用户控件

public partial class MyWpfControl : UserControl 
{ 
    SomeDisposableObject x; 

    // where does this code go? 
    void Somewhere() 
    { 
     if (x != null) 
     { 
      x.Dispose(); 
      x = null; 
     } 

    } 
} 

到目前为止我发现的唯一解决方案是订阅Dispatcher的ShutdownStarted事件。这是一个合理的方法吗?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; 
+0

什么用户控制的空载事件? – akjoshi 2010-12-06 13:56:29

+2

@akjoshi:MSDN说:Unloaded事件可能根本不会被提出。它也可能不止一次被触发,也就是当用户改变主题时。 – Dudu 2011-03-12 12:01:56

+0

虽然您可以在用户控件上实现IDisposable接口,但不保证您的第三方将调用Dispose模式实现的dispose方法。如果您坚持原生资源(例如文件流),则应考虑使用终结器。 – Philippe 2013-03-08 21:51:57

回答

51
+0

嗯,我希望能有比这更干净的方式,但现在看起来这是最好的做法。 – 2009-09-04 06:41:46

+28

但是,如果UserControl在应用程序死亡之前死亡? Dispatcher只会在应用程序执行时放弃,对吧? – 2009-11-12 15:21:37

+0

完全同意,但我不明白为什么OP需要处理控件。听起来很奇怪 – 2012-11-07 14:30:37

-3

UserControl有一个析构函数,为什么不使用它?

~MyWpfControl() 
    { 
     // Dispose of any Disposable items here 
    } 
10

你必须小心使用析构函数。这将在GC终结器线程上调用。在某些情况下,你释放的资源可能不喜欢在与创建它不同的线程上发布。

4

我的场景有点不同,但意图是相同的我想知道什么时候托管我的用户控件的父窗口关闭/关闭视图(即我的用户控件)应该调用演示者oncloseView执行一些功能和执行清理。 (好吧,我们正在WPF PRISM应用程序上实现MVP模式)。

我只是想到在usercontrol的Loaded事件中,我可以将ParentWindowClosing方法连接到父窗口关闭事件。通过这种方式,我的用户控件可以在父窗口关闭时执行相应的操作!

26

Dispatcher.ShutdownStarted事件仅在应用程序结束时被触发。只有在控制失效时才能调用处理逻辑。尤其是在应用程序运行时多次使用控件时,它释放资源。所以ioWint的解决方案是可取的。代码如下:

public MyWpfControl() 
{ 
    InitializeComponent(); 
    Loaded += (s, e) => { // only at this point the control is ready 
     Window.GetWindow(this) // get the parent window 
       .Closing += (s1, e1) => Somewhere(); //disposing logic here 
    }; 
} 
8

我使用以下交互行为向WPF UserControls提供卸载事件。 您可以将行为包含在UserControls XAML中。 因此,您可以在不将逻辑放置在每个UserControl中的情况下拥有该功能。

XAML声明:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 

<i:Interaction.Behaviors> 
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" /> 
</i:Interaction.Behaviors> 

代码隐藏处理程序:

private void UserControlClosingHandler(object sender, EventArgs e) 
{ 
    // to unloading stuff here 
} 

行为的代码:

/// <summary> 
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing. 
/// </summary> 
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += UserControlLoadedHandler; 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.Loaded -= UserControlLoadedHandler; 
     var window = Window.GetWindow(AssociatedObject); 
     if (window != null) 
      window.Closing -= WindowClosingHandler; 
    } 

    /// <summary> 
    /// Registers to the containing windows Closing event when the UserControl is loaded. 
    /// </summary> 
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e) 
    { 
     var window = Window.GetWindow(AssociatedObject); 
     if (window == null) 
      throw new Exception(
       "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used." 
        .FormatWith(AssociatedObject.GetType().Name)); 

     window.Closing += WindowClosingHandler; 
    } 

    /// <summary> 
    /// The containing window is closing, raise the UserControlClosing event. 
    /// </summary> 
    private void WindowClosingHandler(object sender, CancelEventArgs e) 
    { 
     OnUserControlClosing(); 
    } 

    /// <summary> 
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing. 
    /// </summary> 
    public event EventHandler UserControlClosing; 

    protected virtual void OnUserControlClosing() 
    { 
     var handler = UserControlClosing; 
     if (handler != null) 
      handler(this, EventArgs.Empty); 
    } 
}