WPF/MVVM下SaveAndClose按钮的错误处理及窗口关闭实现问询
WPF/MVVM 实现SaveAndClose功能的解决方案
你目前从WinForms转WPF/MVVM开发,需要实现Customer模态窗口的SaveAndClose按钮功能,现有代码已定义命令绑定,但遇到状态传递和窗口关闭逻辑的问题,以下是具体解决方案:
问题1:ViewModel如何传递保存状态及错误信息(替代WinForms的返回值方式)
不用依赖异常传递状态,直接在ViewModel里维护两个属性,通过INotifyPropertyChanged通知View状态变化:
- 先确保
vmCustomer类实现INotifyPropertyChanged接口(WPF MVVM基础要求):
public class vmCustomer : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } // 原有代码... }
- 添加保存状态和错误信息属性:
private bool _isSaveSuccessful; public bool IsSaveSuccessful { get => _isSaveSuccessful; set { _isSaveSuccessful = value; OnPropertyChanged(nameof(IsSaveSuccessful)); } } private string _saveErrorMessage; public string SaveErrorMessage { get => _saveErrorMessage; set { _saveErrorMessage = value; OnPropertyChanged(nameof(SaveErrorMessage)); } }
- 修改
UpdateCustomer方法,不再抛异常,而是设置状态属性:
void UpdateCustomer() { Console.WriteLine($"vmCustomer.UpdateCustomer _editMode={_editMode}"); // 每次保存前重置状态 IsSaveSuccessful = false; SaveErrorMessage = string.Empty; try { switch (_editMode) { case enumEditMode.Add: if (!_mCustomer.Insert(true)) { SaveErrorMessage = "无法插入客户记录"; return; } _editMode = enumEditMode.Edit; break; case enumEditMode.Edit: if (!_mCustomer.Update(true)) { SaveErrorMessage = "无法更新客户记录"; return; } break; case enumEditMode.Delete: if (!_mCustomer.Delete(true)) { SaveErrorMessage = "无法删除客户记录"; return; } break; } // 保存成功,标记状态 IsSaveSuccessful = true; } catch (Exception ex) { // 捕获意外异常,设置错误信息 SaveErrorMessage = $"保存失败:{ex.Message}"; } }
问题2:View如何根据保存状态决定关闭窗口或显示错误
提供两种常用实现方式,按需选择:
方式1:代码后置监听属性变化(简单直接)
在Customer.xaml.cs中,订阅ViewModel的属性变化事件,根据状态执行操作:
public partial class CustomerWindow : Window { public CustomerWindow() { InitializeComponent(); DataContextChanged += CustomerWindow_DataContextChanged; } private void CustomerWindow_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { // 移除旧ViewModel的事件订阅 if (e.OldValue is INotifyPropertyChanged oldVm) { oldVm.PropertyChanged -= ViewModel_PropertyChanged; } // 订阅新ViewModel的事件 if (e.NewValue is INotifyPropertyChanged newVm) { newVm.PropertyChanged += ViewModel_PropertyChanged; } } private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(vmCustomer.IsSaveSuccessful)) { var vm = sender as vmCustomer; if (vm.IsSaveSuccessful) { this.Close(); } else if (!string.IsNullOrEmpty(vm.SaveErrorMessage)) { MessageBox.Show(vm.SaveErrorMessage, "保存错误", MessageBoxButton.OK, MessageBoxImage.Error); } } } }
方式2:使用行为实现无代码后置(更贴合MVVM)
如果不想写代码后置,可以用Microsoft.Xaml.Behaviors.Wpf包实现纯XAML逻辑:
- 先安装NuGet包:
Microsoft.Xaml.Behaviors.Wpf - 在XAML中添加命名空间:
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
- 给窗口添加行为触发器:
<Window ...> <i:Interaction.Triggers> <!-- 保存成功时关闭窗口 --> <i:PropertyChangedTrigger Binding="{Binding IsSaveSuccessful}"> <i:ConditionBehavior> <i:ConditionalExpression> <i:ComparisonCondition LeftOperand="{Binding IsSaveSuccessful}" Operator="Equal" RightOperand="True"/> </i:ConditionalExpression> </i:ConditionBehavior> <i:CallMethodAction TargetObject="{Binding RelativeSource={RelativeSource AncestorType=Window}}" MethodName="Close"/> </i:PropertyChangedTrigger> <!-- 保存失败时显示错误弹窗 --> <i:PropertyChangedTrigger Binding="{Binding SaveErrorMessage}"> <i:ConditionBehavior> <i:ConditionalExpression> <i:ComparisonCondition LeftOperand="{Binding SaveErrorMessage}" Operator="NotEqual" RightOperand=""/> </i:ConditionalExpression> </i:ConditionBehavior> <i:MessageBoxAction Caption="保存错误" Text="{Binding SaveErrorMessage}" Image="Error"/> </i:PropertyChangedTrigger> </i:Interaction.Triggers> <!-- 窗口原有内容 --> </Window>
最后给CommandSaveAndClose绑定对应逻辑,复用UpdateCustomer方法即可:
public ICommand CommandSaveAndClose { get { return new RelayCommand(() => { UpdateCustomer(); // 关闭逻辑交给View根据状态处理 }, () => CanUpdateCustomer()); } }
内容的提问来源于stack exchange,提问作者Mark Roworth
相关产品推荐
相关产品推荐

