MVVM获得ContentPresenter和CancelEdits的验证
本文关键字:验证 CancelEdits 获得 ContentPresenter MVVM | 更新日期: 2023-09-27 18:01:51
我已经为你建立了一个简单的TestClass:
类:
public abstract class Person : INotifyPropertyChanged
public class Adult : Person
public class Child : Person
- 人:名+姓
- 成人:公司 <
- 孩子:学校/gh>
我将此数据存储在ObservableCollection<Person>
中,并希望在我的窗口中显示它:
<ListView ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}" Grid.Column="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock>
<Run Text="{Binding FirstName}"/>
<Run Text="{Binding LastName}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我在ContentPresenter
中显示的选中的一个:
<ContentPresenter Content="{Binding SelectedPerson}">
<ContentPresenter.Resources>
<DataTemplate DataType="{x:Type local:Adult}">
<StackPanel>
<TextBlock Text="First Name:"/>
<TextBox>
<TextBox.Text>
<Binding Path="FirstName">
<Binding.ValidationRules>
<local:NotEmptyRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBlock Text="Last Name:"/>
<TextBox Text="{Binding LastName}"/> <!-- Validation same as FirstName -->
<TextBlock Text="Company:"/>
<TextBox Text="{Binding Company}"/>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Child}">
<StackPanel>
<TextBlock Text="First Name:"/>
<TextBox Text="{Binding FirstName}"/> <!-- Validation same as above-->
<TextBlock Text="Last Name:"/>
<TextBox Text="{Binding LastName}"/> <!-- Validation same as above-->
<TextBlock Text="School:"/>
<TextBox Text="{Binding School}"/>
</StackPanel>
</DataTemplate>
</ContentPresenter.Resources>
</ContentPresenter>
现在谁能告诉我如何取消我的编辑(CancelCommand)或保存他们(SaveCommand)在正确的mvvm方式。
现在我的程序在文本框失去焦点时保存它们,并且它们不能撤消。
谁能给我一个例子吗?
而且我不知道我的输入是无效的:我试过了:
private void SaveCommand_Execute()
{
//this is the current window
MessageBox.Show(string.Format("Entry is {0}valid", IsValid(this) ? "" : "not "), "Validation", MessageBoxButton.OK, MessageBoxImage.Information);
}
private bool IsValid(DependencyObject obj)
{
return !Validation.GetHasError(obj) && LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>().All(IsValid);
}
但是即使我的TextBox显示错误,我的函数告诉我条目是有效的。
谢谢你的帮助!
如果你想要验证,你需要在你的实体上实现INotifyDataErrorInfo
。如果要恢复更改,则需要实现IRevertibleChangeTracking
。如果你以前从来没有做过,这两件事都不容易。
还有另一种方法来解决接受/取消问题。当您开始编辑Person
时,将所有数据复制到PersonViewModel
。然后,您将数据库到PersonViewModel
,当用户单击保存时,将数据复制回Person
,当用户单击取消时,只需忽略更改。
PersonViewModel
类不是强制性的,您可以创建新的实例Person
,但PersonViewModel
在UI逻辑上给了您更多的灵活性。例如,您可以在表示层拥有密码和重复密码字段,但在业务实体中您只希望拥有密码。
撤消更改的解决方案:
public abstract class Person : INotifyPropertyChanged, ICloneable, IEditableObject
已实现接口成员:
Person _Backup = null;
public object Clone()
{
return MemberwiseClone();
}
public void BeginEdit()
{
_Backup = Clone() as Person;
HasChanges = false;
}
public void CancelEdit()
{
foreach (var Prop in GetType().GetProperties())
{
Prop.SetValue(this, Prop.GetValue(_Backup));
}
HasChanges = false;
}
public void EndEdit()
{
_Backup = null;
HasChanges = false;
}
在ViewModel: private const string SelectedPersonPropertyName = "SelectedPerson";
private Person _SelectedPerson;
public Person SelectedPerson
{
get
{
return _SelectedPerson;
}
set
{
if (_SelectedPerson != null)
{
_SelectedPerson.EndEdit();
}
if (value != null)
{
value.BeginEdit();
}
_SelectedPerson = value;
RaisePropertyChanged(SelectedPersonPropertyName);
}
}
实现我的验证规则:
private const string FirstNamePropertyName = "FirstName";
private string _FirstName;
public string FirstName
{
get
{
return _FirstName;
}
set
{
if (_FirstName == value)
return;
ValidationResult _Result = _NotEmptyRule.Validate(value, System.Globalization.CultureInfo.CurrentCulture);
if (!_Result.IsValid)
{
AddError(FirstNamePropertyName, ValueIsNullOrBlank);
}
else
{
RemoveError(FirstNamePropertyName, ValueIsNullOrBlank);
}
_FirstName = value;
HasChanges = true;
RaisePropertyChanged(FirstNamePropertyName);
}
}
private const string ValueIsNullOrBlank = "ValueIsNullOrBlank";
private NotEmptyRule _NotEmptyRule = new NotEmptyRule();
private Dictionary<string, List<object>> _Errors = new Dictionary<string, List<object>>();
protected void AddError(string PropertyName, object Error)
{
if (!_Errors.ContainsKey(PropertyName))
{
_Errors[PropertyName] = new List<object>();
}
if (!_Errors[PropertyName].Contains(Error))
{
_Errors[PropertyName].Add(Error);
RaiseErrorsChanged(PropertyName);
}
}
protected void RemoveError(string PropertyName, object Error)
{
if (_Errors.ContainsKey(PropertyName) && _Errors[PropertyName].Contains(Error))
{
_Errors[PropertyName].Remove(Error);
if (_Errors[PropertyName].Count == 0)
{
_Errors.Remove(PropertyName);
}
RaiseErrorsChanged(PropertyName);
}
}
public void RaiseErrorsChanged(string PropertyName)
{
if (ErrorsChanged != null)
ErrorsChanged(this, new DataErrorsChangedEventArgs(PropertyName));
}
public IEnumerable GetErrors(string PropertyName)
{
if (String.IsNullOrEmpty(PropertyName) ||
!_Errors.ContainsKey(PropertyName)) return null;
return _Errors[PropertyName];
}
public bool HasErrors
{
get { return _Errors.Count > 0; }
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
private const string HasChangesPropertyName = "HasChanges";
private bool _HasChanges;
public bool HasChanges
{
get
{
return _HasChanges;
}
set
{
_HasChanges = value;
RaisePropertyChanged(HasChangesPropertyName);
}
}
我在这里唯一的问题:我不克隆回我的私人字段(只是我的属性)有人知道这里的帮助吗?