Ответ 1
Интересное сообщение в блоге здесь:
http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx
Он упоминает о подписке на Dispatcher.ShutdownStarted, чтобы распоряжаться вашими ресурсами.
Я создал пользовательский пользовательский элемент управления 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;
Интересное сообщение в блоге здесь:
http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx
Он упоминает о подписке на Dispatcher.ShutdownStarted, чтобы распоряжаться вашими ресурсами.
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
};
}
Вы должны быть осторожны, используя деструктор. Это будет вызвано в потоке Finalizer GC. В некоторых случаях ресурсы, которые ваше освобождение может не нравиться, выпущены в другом потоке из того, на котором они были созданы.
Я использую следующее 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>
Обработчик 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);
}
}
Мой сценарий немного отличается, но намерение - это то же самое, что я хотел бы знать, когда родительское окно, в котором находится мой пользовательский элемент управления, закрывается/закрывается, так как представление (то есть мое пользовательское управление) должно вызывать докладчиков oncloseView для выполнения некоторых функций и выполнения очистить. (хорошо мы реализуем шаблон MVP в приложении WPF PRISM).
Я просто понял, что в событии Loaded пользовательского контроля я могу подключить метод ParentWindowClosing к событию закрытия родительских окон. Таким образом, мой Usercontrol может знать, когда окно родителя закрывается и действует соответствующим образом!
Я думаю, что разгрузка называется все, но на самом деле существуют в 4.7. Но, если вы играете со старыми версиями .Net, попробуйте сделать это в вашем методе загрузки:
e.Handled = true;
Я не думаю, что старые версии будут выгружаться до тех пор, пока загрузка не будет обработана. Просто отправляю сообщения, потому что я вижу, что другие все еще задают этот вопрос, и не рассматривали это как решение. Я касаюсь .Net только несколько раз в год, и столкнулся с этим несколько лет назад. Но мне интересно, не вызывается ли так просто, как выгрузить, пока загрузка не закончится. Похоже, это работает для меня, но опять же в более новых .Net он всегда вызывает unload, даже если загрузка не помечена как обработанная.
Пользователь UserControl имеет деструктор, почему бы вам не использовать его?
~MyWpfControl()
{
// Dispose of any Disposable items here
}