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显示错误,我的函数告诉我条目是有效的。

谢谢你的帮助!

MVVM获得ContentPresenter和CancelEdits的验证

如果你想要验证,你需要在你的实体上实现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);
        }
    }

我在这里唯一的问题:我不克隆回我的私人字段(只是我的属性)有人知道这里的帮助吗?