Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 处理WPF用户控件_C#_.net_Wpf_User Controls_Dispose - Fatal编程技术网

C# 处理WPF用户控件

C# 处理WPF用户控件,c#,.net,wpf,user-controls,dispose,C#,.net,Wpf,User Controls,Dispose,我已经创建了一个自定义WPF用户控件,该控件将由第三方使用。我的控件有一个可丢弃的私有成员,我希望确保在包含窗口/应用程序关闭后始终调用它的dispose方法。但是,UserControl不是一次性的 我尝试实现IDisposable接口并订阅卸载的事件,但在主机应用程序关闭时两者都没有被调用。MSDN表示可能根本不会引发卸载的事件。而且它也可能会被多次触发,即当用户更改主题时 如果可能的话,我不想依赖我控件的使用者记住调用特定的Dispose方法 public partial class M

我已经创建了一个自定义WPF用户控件,该控件将由第三方使用。我的控件有一个可丢弃的私有成员,我希望确保在包含窗口/应用程序关闭后始终调用它的dispose方法。但是,UserControl不是一次性的

我尝试实现IDisposable接口并订阅卸载的事件,但在主机应用程序关闭时两者都没有被调用。MSDN表示可能根本不会引发卸载的事件。而且它也可能会被多次触发,即当用户更改主题时

如果可能的话,我不想依赖我控件的使用者记住调用特定的Dispose方法

 public partial class MyWpfControl : UserControl
 {
     SomeDisposableObject x;

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

     }
 }
到目前为止,我找到的唯一解决方案是订阅Dispatcher的ShutdowStart事件。这是否合理的做法

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

有趣的博文如下:


它提到订阅以处置您的资源。

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

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

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

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


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

Dispatcher.ShutdowStart
事件仅在应用程序结束时触发。在控件停止使用时调用处理逻辑是值得的。特别是,当在应用程序运行时多次使用控件时,它会释放资源。因此,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
     };
}

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

XAML声明:

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

<i:Interaction.Behaviors>
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" />
</i:Interaction.Behaviors>
行为准则:

/// <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);
    }
}
//
///当的包含窗口关闭时,此行为引发事件。
/// 
公共类UserControlSupportsUnloadingEventBehavior:System.Windows.Interactivity.Behavior
{
受保护的覆盖无效附加()
{
AssociatedObject.Loaded+=UserControlLoadedHandler;
}
附加时受保护的覆盖无效()
{
AssociatedObject.Loaded-=UserControlLoadedHandler;
var window=window.GetWindow(AssociatedObject);
如果(窗口!=null)
window.Closing-=WindowClosingHandler;
}
/// 
///加载UserControl时注册到包含windows关闭事件。
/// 
私有void UserControlLoadHandler(对象发送方,RoutedEventArgs e)
{
var window=window.GetWindow(AssociatedObject);
如果(窗口==null)
抛出新异常(
“UserControl{0}不包含在窗口中。不能使用UserControlSupportsLoadingEventBehavior。”
.FormatWith(AssociatedObject.GetType().Name));
window.Closing+=WindowClosingHandler;
}
/// 
///包含窗口正在关闭,引发UserControlClosing事件。
/// 
私有void WindowClosingHandler(对象发送方,CancelEventArgs e)
{
OnUserControlClosing();
}
/// 
///关联的包含窗口关闭时将引发此事件。
/// 
公共事件事件处理程序UserControlClosing;
受保护的虚拟void OnUserControlClosing()
{
var handler=UserControlClosing;
if(处理程序!=null)
处理程序(此,EventArgs.Empty);
}
}

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

e.Handled = true;

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

我希望有一种更干净的方法,但现在看来这是最好的方法。但是如果UserControl在应用程序死前就死了怎么办?Dispatcher只会在应用程序关闭时关闭,对吗?因为许多控件重用COM组件或其他非托管资源,而这些组件或资源的编码不是为了无限期地挂起,或在线程池线程上完成,并且期望/需要确定性释放。在Windows应用商店应用程序中,ShutdowStarted不存在。或者您需要取消引用事件处理程序,或者您需要停止在该控件中启动的线程,…这似乎不起作用。我只是尝试了这种方法,但它从未被调用。这不是析构函数,而是终结器。您总是将终结器和Dispose成对实现,否则会有泄漏的风险。而且,在终结器中,您应该只清理非托管对象,而不清理托管对象,因为终结器在GC线程中以未指定的顺序运行,因此托管对象可能会提前终结,并且它们的Dispose()可能具有线程关联性。这是我找到的关于Finalize和Dispose的最好解释。它确实值得一读。虽然你可以实现IDi
e.Handled = true;