Утилизация пользовательских элементов управления WPF - PullRequest
111 голосов
/ 02 февраля 2009

Я создал пользовательский пользовательский элемент управления 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;
         }

     }
 }

Единственное решение, которое я нашел, - это подписаться на событие Dispatcher ShutdownStarted. Это разумный подход?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

Ответы [ 7 ]

54 голосов
/ 02 февраля 2009

Интересное сообщение в блоге здесь:

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

В нем упоминается подписка на Dispatcher.ShutdownStarted для распоряжения вашими ресурсами.

33 голосов
/ 18 декабря 2012

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
     };
}
13 голосов
/ 08 июля 2009

Вы должны быть осторожны, используя деструктор. Это будет вызвано в потоке финализатора GC. В некоторых случаях ресурсам, которые освобождаются при освобождении, может не понравиться выпуск в потоке, отличном от того, в котором они были созданы.

10 голосов
/ 22 октября 2014

Я использую следующее поведение интерактивности, чтобы предоставить событие выгрузки для WPF UserControls. Вы можете включить поведение в XAML UserControls. Таким образом, вы можете использовать эту функциональность, не помещая логику в каждый элемент UserControl.

XAML декларация:

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

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

Обработчик CodeBehind:

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 голосов
/ 04 августа 2011

Мой сценарий немного отличается, но намерение такое же, я хотел бы знать, когда родительское окно, в котором размещается мой пользовательский элемент управления, закрывается / закрывается, так как представление (т.е. мой usercontrol) должно вызывать докладчиков oncloseView для выполнения некоторых функций и убирать (мы реализуем шаблон MVP в приложении WPF PRISM).

Я только что понял, что в событии Loaded пользовательского элемента управления я могу подключить свой метод ParentWindowClosing к событию закрытия родительского окна. Таким образом, мой Usercontrol может знать, когда родительское окно закрывается, и действовать соответственно!

0 голосов
/ 31 мая 2018

Я думаю, что unload называется всем, но трудно существует в 4.7. Но, если вы играете со старыми версиями .Net, попробуйте сделать это в вашем методе загрузки:

e.Handled = true;

Я не думаю, что старые версии будут выгружаться до тех пор, пока загрузка не будет обработана. Просто отправляю сообщения, потому что я вижу, что другие все еще задают этот вопрос, и не рассматривали это как решение. Я касаюсь .Net только несколько раз в год, и столкнулся с этим несколько лет назад. Но мне интересно, не так ли просто вызвать unload, пока загрузка не закончится. Похоже, это работает для меня, но опять же в более новых .Net он всегда вызывает unload, даже если загрузка не помечена как обработанная.

0 голосов
/ 02 февраля 2009

UserControl имеет деструктор, почему бы вам не использовать его?

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