如何在点击取消按钮(或右上角的X或Esc)后取消退出特定表格?
WPF:
b
视图模型:
<Window
...
x:Class="MyApp.MyView"
...
/>
<Button Content="Cancel" Command="{Binding CancelCommand}" IsCancel="True"/>
</Window>
目前的代码不起作用。如果用户选择“不”,我希望用户保持当前状态。在弹出对话框中。 此外,重写CanExecute并没有帮助。它只是禁用按钮。我想允许用户点击按钮,但随后通知他/她,数据将丢失。 也许我应该在按钮上分配一个事件监听器?
编辑:
我在“取消”按钮上设置了弹出窗口。但我仍然无法管理Esc或X按钮(右上角)。我似乎对“取消”按钮感到困惑,因为当我点击X按钮或Esc时执行了Execute方法。
EDIT2:
我改变了问题。它是如何取消取消按钮&#39;。但是,它并不是我想要的。我需要取消Esc或X按钮。 在&#39; MyViewModel&#39;我补充说:
public class MyViewModel : Screen {
private CancelCommand cancelCommand;
public CancelCommand CancelCommand {
get { return cancelCommand; }
}
public MyViewModel() {
cancelCommand = new CancelCommand(this);
}
}
public class CancelCommand : ICommand {
public CancelCommand(MyViewModel viewModel) {
this.viewModel = viewModel;
}
public override void Execute(object parameter) {
if (true) { // here is a real condition
MessageBoxResult messageBoxResult = System.Windows.MessageBox.Show(
"Really close?", "Warning",
System.Windows.MessageBoxButton.YesNo);
if (messageBoxResult == MessageBoxResult.No) { return; }
}
viewModel.TryClose(false);
}
public override bool CanExecute(object parameter) {
return true;
}
}
这解决了我的问题。但是,我需要ICommand来理解,单击了哪个按钮,保存或取消。有没有办法消除事件的使用?
答案 0 :(得分:6)
您正在尝试在ViewModel类中执行View的工作。让您的View类处理结束请求以及是否应该取消它。
要取消关闭窗口,您可以订阅Closing
视图事件,并在显示CancelEventArgs.Cancel
后将MessageBox
设置为true。
以下是一个例子:
<Window
...
x:Class="MyApp.MyView"
Closing="OnClosing"
...
/>
</Window>
代码背后:
private void OnClosing(object sender, CancelEventArgs e)
{
MessageBoxResult result = MessageBox.Show("Really close?", "Warning", MessageBoxButton.YesNo);
if (result != MessageBoxResult.Yes)
{
e.Cancel = true;
}
bool shouldClose = ((MyViewModel) DataContext).TryClose(false);
if(!shouldClose)
{
e.Cancel = true;
}
}
答案 1 :(得分:1)
我不是MVVM专家,但我认为Yusufs的答案不是完全MVVM。另一方面,Torpederos的答案对于仅紧密抵消而言有点复杂。这是我的方法。 在此示例中,我订阅了关闭事件,但始终被取消
private void OnClosing(object sender, CancelEventArgs e)
{
e.Cancel = true;
return;
}
在XAML中,我添加了这个
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding Close}" />
</i:EventTrigger>
</i:Interaction.Triggers>
最后是视图模型
public ICommand Close { get; set; }
Close = new RelayCommand(CommandClose);
private void CommandClose(object sender)
{
if (Dirty)
{
// Save your data here
}
Environment.Exit(0);
}
在这种方法中,关闭事件首先触发。那取消了结账。之后,将调用交互触发器,并通过RelayCommand触发视图模型中的代码。 在视图模型中,我可以使用视图中不可访问的Dirty标志。
答案 2 :(得分:0)
可以在in the article of Nish Nishant上找到以“视图模型”方式执行此操作的一个很好的例子,他在那里使用附加属性来通过命令连接窗口事件。
附加行为的示例代码(代码的作者:Nish Nishant)
public class WindowClosingBehavior {
public static ICommand GetClosed(DependencyObject obj) {
return (ICommand)obj.GetValue(ClosedProperty);
}
public static void SetClosed(DependencyObject obj, ICommand value) {
obj.SetValue(ClosedProperty, value);
}
public static readonly DependencyProperty ClosedProperty
= DependencyProperty.RegisterAttached(
"Closed", typeof(ICommand), typeof(WindowClosingBehavior),
new UIPropertyMetadata(new PropertyChangedCallback(ClosedChanged)));
private static void ClosedChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) {
Window window = target as Window;
if (window != null) {
if (e.NewValue != null) {
window.Closed += Window_Closed;
}
else {
window.Closed -= Window_Closed;
}
}
}
public static ICommand GetClosing(DependencyObject obj) {
return (ICommand)obj.GetValue(ClosingProperty);
}
public static void SetClosing(DependencyObject obj, ICommand value) {
obj.SetValue(ClosingProperty, value);
}
public static readonly DependencyProperty ClosingProperty
= DependencyProperty.RegisterAttached(
"Closing", typeof(ICommand), typeof(WindowClosingBehavior),
new UIPropertyMetadata(new PropertyChangedCallback(ClosingChanged)));
private static void ClosingChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) {
Window window = target as Window;
if (window != null) {
if (e.NewValue != null) {
window.Closing += Window_Closing;
}
else {
window.Closing -= Window_Closing;
}
}
}
public static ICommand GetCancelClosing(DependencyObject obj) {
return (ICommand)obj.GetValue(CancelClosingProperty);
}
public static void SetCancelClosing(DependencyObject obj, ICommand value) {
obj.SetValue(CancelClosingProperty, value);
}
public static readonly DependencyProperty CancelClosingProperty
= DependencyProperty.RegisterAttached(
"CancelClosing", typeof(ICommand), typeof(WindowClosingBehavior));
static void Window_Closed(object sender, EventArgs e) {
ICommand closed = GetClosed(sender as Window);
if (closed != null) {
closed.Execute(null);
}
}
static void Window_Closing(object sender, CancelEventArgs e) {
ICommand closing = GetClosing(sender as Window);
if (closing != null) {
if (closing.CanExecute(null)) {
closing.Execute(null);
}
else {
ICommand cancelClosing = GetCancelClosing(sender as Window);
if (cancelClosing != null) {
cancelClosing.Execute(null);
}
e.Cancel = true;
}
}
}
}
示例如何绑定命令:
<Window
x:Class="WindowClosingDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nsmvvm="clr-namespace:NS.MVVM"
nsmvvm:WindowClosingBehavior.Closed="{Binding ClosedCommand}"
nsmvvm:WindowClosingBehavior.Closing="{Binding ClosingCommand}"
nsmvvm:WindowClosingBehavior.CancelClosing="{Binding CancelClosingCommand}">
命令“ ClosedCommand”,“ ClosingCommand”和“ CancelClosingCommand”应在单独的视图模型中定义。
internal class MainViewModel : ViewModelBase {
private ObservableCollection<string> log = new ObservableCollection<string>();
public ObservableCollection<string> Log {
get { return log; }
}
private DelegateCommand exitCommand;
public ICommand ExitCommand {
get {
if (exitCommand == null) {
exitCommand = new DelegateCommand(Exit);
}
return exitCommand;
}
}
private void Exit() {
Application.Current.Shutdown();
}
private DelegateCommand closedCommand;
public ICommand ClosedCommand {
get {
if (closedCommand == null) {
closedCommand = new DelegateCommand(Closed);
}
return closedCommand;
}
}
private void Closed() {
log.Add("You won't see this of course! Closed command executed");
MessageBox.Show("Closed");
}
private DelegateCommand closingCommand;
public ICommand ClosingCommand {
get {
if (closingCommand == null) {
closingCommand = new DelegateCommand(ExecuteClosing, CanExecuteClosing);
}
return closingCommand;
}
}
private void ExecuteClosing() {
log.Add("Closing command executed");
MessageBox.Show("Closing");
}
private bool CanExecuteClosing() {
log.Add("Closing command execution check");
return MessageBox.Show("OK to close?", "Confirm", MessageBoxButton.YesNo) == MessageBoxResult.Yes;
}
private DelegateCommand cancelClosingCommand;
public ICommand CancelClosingCommand {
get {
if (cancelClosingCommand == null) {
cancelClosingCommand = new DelegateCommand(CancelClosing);
}
return cancelClosingCommand;
}
}
private void CancelClosing() {
log.Add("CancelClosing command executed");
MessageBox.Show("CancelClosing");
}
}
答案 3 :(得分:0)
这是直接从 ViewModel 取消关闭窗口的另一个示例。
查看:
<Window x:Class="WpfApplicationMvvmLight.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<cmd:EventToCommand Command="{Binding Path=ClosingCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<TextBlock>content...</TextBlock>
</Grid>
视图模型:
using GalaSoft.MvvmLight.CommandWpf;
using System.ComponentModel;
using System.Windows;
namespace WpfApplicationMvvmLight
{
class SampleViewModel
{
public SampleViewModel() {
_closingCommand = new RelayCommand<CancelEventArgs>(OnClosingCommand);
}
private RelayCommand<CancelEventArgs> _closingCommand;
public RelayCommand<CancelEventArgs> ClosingCommand {
get {
return _closingCommand;
}
}
private void OnClosingCommand(CancelEventArgs e) {
//display your custom message box here..
var result = MessageBox.Show("Do you want to close?", "", MessageBoxButton.YesNoCancel);
//set e.Cancel to true to prevent the window from closing
e.Cancel = result != MessageBoxResult.Yes;
}
}
}
背后的代码:
using System.Windows;
namespace WpfApplicationMvvmLight
{
public partial class MainWindow : Window
{
public MainWindow() {
InitializeComponent();
this.DataContext = new SampleViewModel();
}
}
}
这是参考。 MVVM close window event