在将旧的 WinForms 应用程序移植到 WPF 时遇到了这个问题。我认为要记住的重要一点是,WPF 通过在视图模型和带有事件的视图(即,等)之间发出信号来完成它在后台所做的很多INotifyPropertyChanged.PropertyChanged
事情INotifyDataErrorInfo.ErrorsChanged
。我对这个问题的解决方案是拿那个例子并用它来运行。在我的视图模型中:
/// <summary>
/// Occurs before the record is deleted
/// </summary>
public event CancelEventHandler DeletingRecord;
/// <summary>
/// Occurs before record changes are discarded (i.e. by a New or Close operation)
/// </summary>
public event DiscardingChangesEvent DiscardingChanges;
然后视图可以侦听这些事件,如果需要提示用户,如果指示这样做,则取消事件。
请注意,这CancelEventHandler
是由框架为您定义的。但是,对于DiscardingChanges
,您需要一个三态结果来指示您希望如何处理操作(即保存更改、放弃更改或取消您正在执行的操作)。为此,我自己做了一个:
public delegate void DiscardingChangesEvent(object sender, DiscardingChangesEventArgs e);
public class DiscardingChangesEventArgs
{
public DiscardingChangesOperation Operation { get; set; } = DiscardingChangesOperation.Cancel;
}
public enum DiscardingChangesOperation
{
Save,
Discard,
Cancel
}
我试图想出一个更好的命名约定,但这是我能想到的最好的。
所以,把它付诸实践看起来像这样:
ViewModel(这实际上是我基于 CRUD 的视图模型的基类):
protected virtual void New()
{
// handle case when model is dirty
if (ModelIsDirty)
{
var args = new DiscardingChangesEventArgs(); // defaults to cancel, so someone will need to handle the event to signal discard/save
DiscardingChanges?.Invoke(this, args);
switch (args.Operation)
{
case DiscardingChangesOperation.Save:
if (!SaveInternal())
return;
break;
case DiscardingChangesOperation.Cancel:
return;
}
}
// continue with New operation
}
protected virtual void Delete()
{
var args = new CancelEventArgs();
DeletingRecord?.Invoke(this, args);
if (args.Cancel)
return;
// continue delete operation
}
看法:
<UserControl.DataContext>
<vm:CompanyViewModel DeletingRecord="CompanyViewModel_DeletingRecord" DiscardingChanges="CompanyViewModel_DiscardingChanges"></vm:CompanyViewModel>
</UserControl.DataContext>
查看代码隐藏:
private void CompanyViewModel_DeletingRecord(object sender, System.ComponentModel.CancelEventArgs e)
{
App.HandleRecordDeleting(sender, e);
}
private void CompanyViewModel_DiscardingChanges(object sender, DiscardingChangesEventArgs e)
{
App.HandleDiscardingChanges(sender, e);
}
还有几个静态方法,它们是每个视图都可以使用的 App 类的一部分:
public static void HandleDiscardingChanges(object sender, DiscardingChangesEventArgs e)
{
switch (MessageBox.Show("Save changes?", "Save", MessageBoxButton.YesNoCancel))
{
case MessageBoxResult.Yes:
e.Operation = DiscardingChangesOperation.Save;
break;
case MessageBoxResult.No:
e.Operation = DiscardingChangesOperation.Discard;
break;
case MessageBoxResult.Cancel:
e.Operation = DiscardingChangesOperation.Cancel;
break;
default:
throw new InvalidEnumArgumentException("Invalid MessageBoxResult returned from MessageBox.Show");
}
}
public static void HandleRecordDeleting(object sender, CancelEventArgs e)
{
e.Cancel = MessageBox.Show("Delete current record?", "Delete", MessageBoxButton.YesNo) == MessageBoxResult.No;
}
将对话框集中在这些静态方法中可以让我们稍后轻松地将它们换成自定义对话框。