C# 处理 WPF 用户控件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/502761/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:52:19  来源:igfitidea点击:

Disposing WPF User Controls

c#.netwpfuser-controlsdispose

提问by Mark Heath

I have created a custom WPF user control which is intended to be used by a third party. My control has a private member which is disposable, and I would like to ensure that its dispose method will always get called once the containing window/application is closed. However, UserControl is not disposable. I tried implementing the IDisposable interface and subscribing to the Unloaded event but neither get called when the host application closes. If at all possible, I don't want to rely on consumers of my control remembering to call a specific Dispose method.

我创建了一个自定义 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;
         }

     }
 }

The only solution I have found so far is to subscribe to the Dispatcher's ShutdownStarted event. Is this a reasonable approach?

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

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

采纳答案by Ray Booysen

回答by Ray Booysen

An UserControl has a Destructor, why don't you use that?

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

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

回答by Ade Miller

You have to be careful using the destructor. This will get called on the GC Finalizer thread. In some cases the resources that your freeing may not like being released on a different thread from the one they were created on.

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

回答by ioWint

My scenario is little different, but the intent is same i would like to know when the parent window hosting my user control is closing/closed as The view(i.e my usercontrol) should invoke the presenters oncloseView to execute some functionality and perform clean up. ( well we are implementing a MVP pattern on a WPF PRISM application).

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

I just figured that in the Loaded event of the usercontrol, i can hook up my ParentWindowClosing method to the Parent windows Closing event. This way my Usercontrol can be aware when the Parent window is being closed and act accordingly!

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

回答by Ilia Barahovski

Dispatcher.ShutdownStartedevent is fired only at the end of application. It's worth to call the disposing logic just when control gets out of use. In particular it frees resources when control is used many times during application runtime. So ioWint's solution is preferable. Here's the code:

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
     };
}

回答by alex.enjoy

I use the following Interactivity Behavior to provide an unloading event to WPF UserControls. You can include the behavior in the UserControls XAML. So you can have the functionality without placing the logic it in every single UserControl.

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

XAML declaration:

XAML 声明:

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

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

CodeBehind handler:

代码隐藏处理程序:

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

Behavior Code:

行为准则:

/// <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);
    }
}

回答by Michael T.

I'm thinking unload is called all but at hard exist in 4.7. But, if you are playing around with older versions of .Net, try doing this in your loading method:

我认为卸载在 4.7 中被称为 all but at hard 。但是,如果您正在使用旧版本的 .Net,请尝试在您的加载方法中执行此操作:

e.Handled = true;

I don't think older versions will unload until loading is handled. Just posting because I see others still asking this question, and haven't seen this proposed as a solution. I only touch .Net a few times a year, and ran into this a few years back. But, I wonder if it's as simple as unload not being called until loading has finished. Seems like it works for me, but again in newer .Net it seems to always call unload even if loading isn't marked as handled.

我认为在处理加载之前不会卸载旧版本。只是发布是因为我看到其他人仍在问这个问题,并且还没有将其视为解决方案。我一年只接触过 .Net 几次,几年前就碰到过。但是,我想知道它是否像在加载完成之前不调用卸载一样简单。似乎它对我有用,但在较新的 .Net 中,即使加载未标记为已处理,它似乎总是调用卸载。