我正在努力实现以下目标:
我有一个表单,用户必须输入姓名、姓氏、地址……以及保存更改按钮。
我想让用户点击保存更改 仅当他确实进行了任何更改时才按下按钮。我发现通过简单地使用 IChangeTracking 它只跟踪用户是否完成了 任意 更改工具,但他是否应将更改恢复回来,这不再反射(reflect)。因此,每当我看到已进行更改时,我都会触发 IEqualityComparer;但是没有运气,因为它给了我以下错误:
An unhandled exception of type 'System.StackOverflowException' occurred in Unknown Module.
这是我的简单类Person:
public class Person : ViewModelBase
{
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
private string _Surname;
public string Surname
{
get { return _Surname; }
set
{
_Surname = value;
OnPropertyChanged("Surname");
}
}
}
这是我的 ViewModelBase 结构:
public abstract class ViewModelBase : INotifyPropertyChanged, IChangeTracking, IEqualityComparer<Person> { public event Action ValueChanged; protected ViewModelBase() { this.PropertyChanged = new PropertyChangedEventHandler(OnNotifiedOfPropertyChanged); ValueChanged += ViewModelBase_ValueChanged; } void ViewModelBase_ValueChanged() {/*do nothing*/ } public bool Equals(Person x, Person y) { if (x == null || y == null) return false; return (x.Name == y.Name && x.Surname == y.Surname); } public int GetHashCode(Person obj) { return obj.GetHashCode(); } private void OnNotifiedOfPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e != null && !String.Equals(e.PropertyName, "IsChanged", StringComparison.Ordinal)) { this.IsChanged = true; } } public void AcceptChanges() { this.IsChanged = false; } public bool IsChanged { get { lock (_notifyingObjectIsChangedSyncRoot) { return _notifyingObjectIsChanged; } } set { lock (_notifyingObjectIsChangedSyncRoot) { _notifyingObjectIsChanged = value; this.OnPropertyChanged("IsChanged"); this.ValueChanged.Invoke(); } } } private bool _notifyingObjectIsChanged; private readonly object _notifyingObjectIsChangedSyncRoot = new Object(); public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string name) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(name));//<<<<<Mentioned Error occures here } } }
最后,这是我设置 ViewModel 的方式:
public class MainViewModel
{
public Person osoba { get; set; }
public Person OldOsoba { get; set; }
public MainViewModel()
{
osoba = new Person();
osoba.Name = "John";
osoba.Surname = "Doe";
osoba.AcceptChanges();
OldOsoba = new Person();
OldOsoba.Name = "John";
OldOsoba.Surname = "Doe";
OldOsoba.AcceptChanges();
osoba.ValueChanged += osoba_ValueChanged;
}
void osoba_ValueChanged()
{
osoba.IsChanged = osoba.Equals(OldOsoba);
}
}
我愿意接受任何建议,因为我不太确定这是否是正确的方法。
最佳答案
这是一个替代方案:
在您的模型中创建 是脏的属性,如果 Name 或 Surname 属性发生更改,该属性将设置为 true:
public class Person : ViewModelBase
{
public string OldName { get; set; }
public string OldSurname { get; set; }
private string _Name;
public string Name
{
get { return _Name; }
set
{
_Name = value;
OnPropertyChanged("Name");
OnPropertyChanged("IsDirty");
}
}
private string _Surname;
public string Surname
{
get { return _Surname; }
set
{
_Surname = value;
OnPropertyChanged("Surname");
OnPropertyChanged("IsDirty");
}
}
public bool IsDirty
{
get
{
return this.Name != this.OldName && this.Surname != this.OldSurname;
}
}
}
注意:为 IsDirty 属性甚至基类使用接口(interface)可能是个好主意。
然后,您可以为您的 ViewModel 实现一个命令,该命令将测试列表中的任何人是否已更改:
public class SaveChangesCommand : ICommand
{
private MainViewModel _viewModel;
public SaveChangesCommand(MainViewModel viewModel)
{
_viewModel = viewModel;
}
public bool CanExecute(object parameter)
{
//People should be an ObservableCollection<Person> in your view model.
return _viewModel.People.Any(x => x.IsDirty);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_viewModel.SaveChanges();
}
}
在您的 View 模型中创建此命令的实例:
public SaveChangesCommand SaveChangesCommand { get; set; }
不要忘记实例化它(在您的构造函数中将是一个好地方)
并在您的 View 中绑定(bind)一个按钮:
<Button Command="{Binding SaveChangesCommand}" Content="Save Changes"/>
现在,有了这一切,当您的任何模型变脏时,保存更改按钮将被启用。单击后,它将调用 保存更改 View 模型中的方法。在这里,您将需要实现保存更改实现并将所有模型重置为默认状态(IsDirty = false)
我建议通过 MVVM 教程 here .
关于c# mvvm IEqualityComparer with IChangeTracking,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27921844/