我从这篇文章中获得了灵感,并将其改编成了一个我正在构建的库,供自己使用(但将公开位于此处:https://github.com/RFBCodeWorks/MvvmControls)。
虽然我的方法有点通过传递给处理程序的“sender”和“eventargs”向ViewModel暴露View,但我使用这种方法只是为了以防其他某些处理需要它。例如,如果处理程序不是ViewModel,而是记录打开/关闭窗口的某个服务,则该服务可能想要了解发送者。如果VM不想知道View,则它只需不检查发送者或参数。
以下是我想出的相关代码,它消除了Code-Behind,并允许在xaml中进行绑定:
Behaviors:WindowBehaviors.IWindowClosingHandler="{Binding ElementName=ThisWindow, Path=DataContext}"
public interface IWindowClosingHandler
{
void OnWindowClosing(object sender, System.ComponentModel.CancelEventArgs e);
void OnWindowClosed(object sender, EventArgs e);
}
public static class WindowBehaviors
{
#region < IWindowClosing >
public static readonly DependencyProperty IWindowClosingHandlerProperty =
DependencyProperty.RegisterAttached(nameof(IWindowClosingHandler),
typeof(IWindowClosingHandler),
typeof(WindowBehaviors),
new PropertyMetadata(null, IWindowClosingHandlerPropertyChanged)
);
public static IWindowClosingHandler GetIWindowClosingHandler(DependencyObject obj) => (IWindowClosingHandler)obj.GetValue(IWindowClosingHandlerProperty);
public static void SetIWindowClosingHandler(DependencyObject obj, IWindowClosingHandler value)
{
if (obj is not null and not Window) throw new ArgumentException($"{nameof(IWindowClosingHandler)} property can only be bound to a {nameof(Window)}");
obj.SetValue(IWindowClosingHandlerProperty, value);
}
private static void IWindowClosingHandlerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window w = d as Window;
if (w is null) return;
if (e.NewValue != null)
{
w.Closing += W_Closing;
w.Closed += W_Closed;
}
else
{
w.Closing -= W_Closing;
w.Closed -= W_Closed;
}
}
private static void W_Closed(object sender, EventArgs e)
{
GetIWindowClosingHandler(sender as DependencyObject)?.OnWindowClosed(sender, e);
}
private static void W_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
GetIWindowClosingHandler(sender as DependencyObject)?.OnWindowClosing(sender, e);
}
#endregion
}