代码之家  ›  专栏  ›  技术社区  ›  Mark Heath

处理WPF用户控件

  •  111
  • Mark Heath  · 技术社区  · 16 年前

    我已经创建了一个自定义的WPF用户控件,它将被第三方使用。我的控件有一个可释放的私有成员,我希望确保在关闭包含的窗口/应用程序后始终调用其Dispose方法。但是,用户控件不是一次性的。我尝试实现IDisposable接口并订阅卸载的事件,但在宿主应用程序关闭时两者都没有被调用。如果可能的话,我不想依赖控件的使用者记住调用特定的Dispose方法。

     public partial class MyWpfControl : UserControl
     {
         SomeDisposableObject x;
    
         // where does this code go?
         void Somewhere() 
         {
             if (x != null)
             {
                 x.Dispose();
                 x = null;
             }
    
         }
     }
    

    到目前为止,我找到的唯一解决方案是订阅调度程序的ShutdownStarted事件。这是一个合理的方法吗?

    this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
    
    7 回复  |  直到 16 年前
        1
  •  54
  •   Ray Booysen    16 年前
        2
  •  33
  •   Ilia Barahovsky    12 年前

    Dispatcher.ShutdownStarted 事件仅在应用程序结束时激发。当控件停止使用时,调用处理逻辑是值得的。尤其是在应用程序运行时多次使用控件时,它释放资源。所以 伊文特 的解决方案更可取。代码如下:

    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
         };
    }
    
        3
  •  13
  •   Ade Miller    16 年前

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

        4
  •  10
  •   alex.enjoy    10 年前

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

    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);
        }
    }
    
        5
  •  5
  •   ioWint    13 年前

    我的场景稍有不同,但我想知道承载我的用户控件的父窗口何时关闭,因为视图(即我的用户控件)应该调用Presenters OnCloseView来执行一些功能并执行清理。(我们正在WPF Prism应用程序上实现MVP模式)。

    我刚刚想到,在用户控件的已加载事件中,我可以将ParentWindowClosing方法连接到父Windows Closing事件。这样,当父窗口关闭时,我的用户控件就可以知道,并相应地执行操作!

        6
  •  0
  •   Michael T    7 年前

    我认为4.7中的“卸载”称为“所有”,但“硬存在”。但是,如果您正在使用旧版本的.NET,请尝试在加载方法中执行此操作:

    e.Handled = true;
    

    我认为在处理加载之前,旧版本不会卸载。只是发帖,因为我看到其他人仍然在问这个问题,而且还没有把这个建议当作解决方案。我一年只接触.NET几次,几年前就遇到了。但是,我想知道这是否和卸载一样简单,直到加载完成后才调用卸载。似乎它对我有用,但在较新的.NET中,它似乎总是调用Unload,即使加载没有标记为已处理。

        7
  •  -3
  •   Frances    16 年前

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

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