2009-02-02 77 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); 
    } 
}