处置WPF用户控件

Mar*_*ath 114 .net c# wpf user-controls dispose

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

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

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

     }
 }
Run Code Online (Sandbox Code Playgroud)

到目前为止,我找到的唯一解决方案是订阅Dispatcher的ShutdownStarted事件.这是一种合理的方法吗?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
Run Code Online (Sandbox Code Playgroud)

Ray*_*sen 56

有趣的博客文章:

http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx

它提到订阅Dispatcher_ShutDownStarted来处理你的资源.

  • 但是,如果UserControl在应用程序死亡之前死亡怎么办?Dispatcher只会在应用程序出现时瘫痪,对吧? (33认同)
  • 因为许多控件重用COM组件或未使用视图编码的其他非托管资源无限期地挂起或在线程池线程上最终确定,并期望/需要确定性释放. (14认同)
  • 或者您需要取消引用事件处理程序,或者您需要停止在该控件中启动的线程,... (6认同)

Ili*_*ski 38

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
     };
}
Run Code Online (Sandbox Code Playgroud)

  • Cœur:在Windows应用商店应用中,您没有使用WPF (8认同)
  • 如果涉及更多的窗户并且主要的窗户永远不会关闭怎么办?或者您的控件托管在多次加载/卸载的页面中?请参阅:http://stackoverflow.com/a/14074116/1345207 (3认同)
  • 窗口可能不会经常关闭。如果控件是列表项的一部分,则将创建/销毁许多控件,直到其父窗口可能关闭。 (2认同)

Ade*_*ler 15

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


ale*_*joy 10

我使用以下Interactivity Behavior为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>
Run Code Online (Sandbox Code Playgroud)

CodeBehind处理程序:

private void UserControlClosingHandler(object sender, EventArgs e)
{
    // to unloading stuff here
}
Run Code Online (Sandbox Code Playgroud)

行为代码:

/// <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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我在这里举起一个标志......如果有什么其他方法取消窗口关闭(可能在你的控件之后订阅,所以`e.Cancel`在到达你的'WindowClosingHandler`委托时仍然是假的)?您的控件将被"卸载"并且窗口仍然打开.我肯定会在'Closed`事件上做这件事,而不是在'Closing`事件上. (5认同)

ioW*_*int 6

我的情况略有不同,但我想知道当托管我的用户控件的父窗口关闭/关闭时,意图是相同的.视图(即我的usercontrol)应该调用oncloseView上的演示者来执行某些功能并执行清理.(我们正在WPF PRISM应用程序上实现MVP模式).

我只是想在usercontrol的Loaded事件中,我可以将ParentWindowClosing方法连接到Parent windows Closing事件.这样我的Usercontrol可以在父窗口关闭时知道并采取相应的行动!