c# mvvm IEqualityComparer 与 IChangeTracking
c# mvvm IEqualityComparer with IChangeTracking
我正在努力实现以下目标:
我有一个表单,用户必须输入姓名、姓氏、地址……以及保存更改按钮。
我想让用户仅在他确实进行了任何更改时才单击 保存更改 按钮。我发现通过简单地使用 IChangeTracking 它只跟踪用户是否对工具进行了 any 更改,但是他是否应该将更改还原回来,这不再反映。因此,每当我看到已进行更改时,我都会触发 IEqualityComparer;但是没有运气,因为它给了我以下错误:
An unhandled exception of type 'System.WhosebugException'
occurred in Unknown Module.
这是我的简单 class 人:
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);
}
}
我愿意接受任何建议,因为我不太确定这是否是正确的方法。
这是一个替代方案:
在您的模型中创建一个 IsDirty 属性,如果 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 属性 使用接口可能是个好主意,甚至是基础 class.
然后,您可以为您的 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();
}
}
在您的视图模型中创建此命令的实例:
public SaveChangesCommand SaveChangesCommand { get; set; }
别忘了实例化它(在你的构造函数中会是个好地方)
并在您的视图中绑定一个按钮:
<Button Command="{Binding SaveChangesCommand}" Content="Save Changes"/>
现在,有了这一切,当您的任何模型变脏时,将启用保存更改按钮。单击后,它将在您的视图模型中调用 SaveChanges 方法。在这里您将需要实现保存更改实现并将所有模型重置为默认状态 (IsDirty = false)
我建议完成 MVVM 教程 here。
我正在努力实现以下目标: 我有一个表单,用户必须输入姓名、姓氏、地址……以及保存更改按钮。 我想让用户仅在他确实进行了任何更改时才单击 保存更改 按钮。我发现通过简单地使用 IChangeTracking 它只跟踪用户是否对工具进行了 any 更改,但是他是否应该将更改还原回来,这不再反映。因此,每当我看到已进行更改时,我都会触发 IEqualityComparer;但是没有运气,因为它给了我以下错误:
An unhandled exception of type 'System.WhosebugException' occurred in Unknown Module.
这是我的简单 class 人:
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);
}
}
我愿意接受任何建议,因为我不太确定这是否是正确的方法。
这是一个替代方案:
在您的模型中创建一个 IsDirty 属性,如果 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 属性 使用接口可能是个好主意,甚至是基础 class.
然后,您可以为您的 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();
}
}
在您的视图模型中创建此命令的实例:
public SaveChangesCommand SaveChangesCommand { get; set; }
别忘了实例化它(在你的构造函数中会是个好地方)
并在您的视图中绑定一个按钮:
<Button Command="{Binding SaveChangesCommand}" Content="Save Changes"/>
现在,有了这一切,当您的任何模型变脏时,将启用保存更改按钮。单击后,它将在您的视图模型中调用 SaveChanges 方法。在这里您将需要实现保存更改实现并将所有模型重置为默认状态 (IsDirty = false)
我建议完成 MVVM 教程 here。