将视图模型方法绑定到视图的 Alt+F4 和"关闭"按钮



我创建了一个自定义方法来关闭视图模型中的表单,并将其绑定到一个按钮。我如何得到默认的关闭按钮在标题栏和Alt+F4运行相同的命令?

public void Close(object parameter)
{
// Check if any field has been edited
if (IsDirty())
{
string message = "You have unsaved changes.nnAre you sure you want to close this form?";
string title = "Close Window";
MessageBoxResult result = MessageBox.Show(message, title, MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (result == MessageBoxResult.Cancel)
return;
}
employeeWindow.Close();
}

我仍然是WPF和MVVM的新手,我只是不理解任何已经存在的解决方案,或者我如何自定义它们来运行上面的代码。

您要查找的是Window上的Closing事件。它的CancelEventArgs带有bool类型的Cancel属性,可以设置为true,这将取消关闭窗口。关闭事件将在使用关闭按钮和按Alt+F4关闭窗口时触发。

后台代码

在代码隐藏场景中,您可以像这样在XAML中添加事件处理程序。

<Window Closing="OnClosing" ...>

然后,您将在代码隐藏中创建此事件处理程序,并相应地设置Cancel属性。

private void OnClosing(object sender, CancelEventArgs e)
{
// Check if any field has been edited
if (IsDirty())
{
string message = "You have unsaved changes.nnAre you sure you want to close this form?";
string title = "Close Window";
MessageBoxResult result = MessageBox.Show(message, title, MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (result == MessageBoxResult.Cancel)
e.Cancel = true;
}
}

Event Trigger (Non MVVM)

在MVVM中,您可以安装Microsoft.Xaml.Behaviors。WpfNuGet包,它是遗留的混合行为(System.Windows.Interactivity)的替代品。您可以使用EventTrigger将事件绑定到视图模型中的命令。在本例中,您直接将CancelEventArgs传递给命令。

<Window ...>
<b:Interaction.Triggers>
<b:EventTrigger EventName="Closing">
<b:InvokeCommandAction Command="{Binding ClosingCommand}"
PassEventArgsToCommand="True"/>
</b:EventTrigger>
</b:Interaction.Triggers>
<!-- ...other markup. -->
</Window>

这个解决方案允许你在视图模型中定义一个命令。

public class MyViewModel
{
public MyViewModel()
{
ClosingCommand = new RelayCommand<CancelEventArgs>(ExecuteClosing);
}
public ICommand ClosingCommand { get; }
private void ExecuteClosing(CancelEventArgs e)
{
string message = "You have unsaved changes.nnAre you sure you want to close this form?";
string title = "Close Window";
MessageBoxResult result = MessageBox.Show(message, title, MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);

if (result == MessageBoxResult.Cancel)
e.Cancel = true;
}
}

我在这里没有提供ICommand实现。有关基础知识的更多信息,请参阅:

  • MVVM - Commands, RelayCommands and EventToCommand

虽然这个解决方案在视图模型上使用命令,但它不是MVVM兼容的,因为消息框是一个视图组件,不能驻留在视图模型中。这同样适用于cancel事件参数。

MVVM行为符合MVVM的方法可能是创建一个行为来移动确认代码。为此,为视图模型创建一个包含IsDirty方法的接口,并在视图模型中实现它。

public interface IStatefulViewModel
{
bool IsDirty();
}
public class MyViewModel : IStatefulViewModel
{
// ...your code.
public bool IsDirty()
{
// ...your checks.
}
}
然后,使用Microsoft.Xaml.Behaviors创建一个行为。WpfNuGet包。这种行为是可重用的,并且封装了与视图模型解耦的关闭逻辑。CaptionMessage依赖属性允许绑定消息框内容。
public class WindowClosingBehavior : Behavior<Window>
{
public static readonly DependencyProperty CaptionProperty = DependencyProperty.Register(
nameof(Caption), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
nameof(Message), typeof(string), typeof(WindowClosingBehavior), new PropertyMetadata(string.Empty));
public string Caption
{
get => (string)GetValue(CaptionProperty);
set => SetValue(CaptionProperty, value);
}
public string Message
{
get => (string)GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Closing += OnClosing;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Closing -= OnClosing;
}
private void OnClosing(object sender, CancelEventArgs e)
{
if (!(AssociatedObject.DataContext is IStatefulViewModel statefulViewModel))
return;
if (!statefulViewModel.IsDirty())
return;
e.Cancel = ConfirmClosing();
}
private bool ConfirmClosing()
{
var result = MessageBox.Show(
Message,
Caption,
MessageBoxButton.OKCancel,
MessageBoxImage.Warning,
MessageBoxResult.Cancel);
return result == MessageBoxResult.Cancel;
}
}

将行为附加到窗口。请注意,您可以在任何窗口上执行此操作。

<Window ...>
<b:Interaction.Behaviors>
<local:WindowClosingBehavior Caption="Close Window"
Message="You have unsaved changes.&#13;&#10;&#13;&#10;Are you sure you want to close this form?"/>
</b:Interaction.Behaviors>
<!-- ...other markup. -->
</Window>

不要被&#13;&#10;字符混淆,它们在XML中是换行符(n)。

最新更新