IDataErrorInfo问题 - 初始属性值

时间:2016-06-01 11:03:26

标签: c# wpf idataerrorinfo

我有一个像往常一样实现IDataErrorInfo接口的ViewModel。

模型

public class Computer : Model
  {
    public Computer(string name, string ip, string mac, string broadcastIp)
    {
      Name = name;
      Ip = ip;
      Mac = mac;
      BroadcastIp = broadcastIp;
    }

    public Computer()
    {
      Name = "neuer Computer";
      Mac = string.Empty;
      Ip = string.Empty;
      BroadcastIp = string.Empty;
    }

    [NotMapped]
    public ComputerState ComputerState { get; set; }

    public string Name { get; set; }

    public string Ip { get; set; }

    public string Mac { get; set; }

    public string BroadcastIp { get; set; }

    public virtual Room Room { get; set; }
   }

视图模型

 public class ComputerViewModel : ViewModel<Computer>, IListItem
  {
    private bool _IsSelected;
    private ComputerOperationMessage _OperationMessage = ComputerOperationMessage.NO_MESSAGE;

    public ComputerViewModel(Computer computer) : base(computer)
    {
    }

    public string Name
    {
      get { return Model.Name; }
      set
      {
        Model.Name = value;
        RaisePropertyChanged(nameof(Name));
      }
    }

    public RoomViewModel Room
    {
      get { return App.EntityManager.Get<RoomViewModel>().FirstOrDefault(r => r.Model.Equals(Model.Room)); }
      set
      {
        Model.Room = value.Model;
        RaisePropertyChanged(nameof(Room));
      }
    }

    public ComputerState State
    {
      get { return Model.ComputerState; }
      set
      {
        if (value.Equals(Model.ComputerState))
          return;

        Model.ComputerState = value;
        RaisePropertyChanged(nameof(State));
      }
    }

    public string Ip
    {
      get { return Model.Ip; }
      set
      {
        Model.Ip = value;
        RaisePropertyChanged(nameof(Ip));
      }
    }

    public string Mac
    {
      get { return Model.Mac; }
      set
      {
        Model.Mac = value;
        RaisePropertyChanged(nameof(Mac));
      }
    }

    public string BroadcastIp
    {
      get { return Model.BroadcastIp; }
      set
      {
        Model.BroadcastIp = value;
        RaisePropertyChanged(nameof(BroadcastIp));
      }
    }

    /// <summary>
    ///   UI indicator when a operation like shutdown, reboot, ping etc. is running
    /// </summary>
    public ComputerOperationMessage OperationMessage
    {
      get { return _OperationMessage; }
      set
      {
        if (value.Equals(_OperationMessage))
          return;

        _OperationMessage = value;
        RaisePropertyChanged(nameof(OperationMessage));
      }
    }

    public bool IsSelected
    {
      get { return _IsSelected; }
      set
      {
        _IsSelected = value;
        RaisePropertyChanged(nameof(IsSelected));
      }
    }

    public override string ToString()
    {
      return Name;
    }

    protected override string ValidateProperty(string property)
    {
      var computers = App.EntityManager.Get<ComputerViewModel>().ToList();

      switch (property)
      {
        case nameof(Name):
          if (string.IsNullOrEmpty(Name))
          {
            return "Bezeichnung erwartet";
          }
          if (computers.Any(c => c.Name == Name))
          {
            return "Bezeichnung bereits vergeben";
          }
          break;
        case nameof(Ip):
          if (string.IsNullOrEmpty(Ip))
          {
            return "Ip erwartet";
          }

          if (!NetworkCommand.ValidateIp(Ip))
          {
            return "Ip ungültig";
          }

          if (computers.Any(c => c.Ip == Ip))
          {
            return "Ip bereits vergeben";
          }
          break;
        case nameof(Mac):
          if (string.IsNullOrEmpty(Mac))
          {
            return "Mac erwartet";
          }

          if (!NetworkCommand.ValidateMac(Mac))
          {
            return "Mac ungültig";
          }
          if (computers.Any(c => c.Mac == Mac))
          {
            return "Mac bereits vergeben";
          }
          break;
        case nameof(BroadcastIp):
          if (string.IsNullOrEmpty(BroadcastIp))
          {
            return "Broadcast Ip erwartet";
          }
          if (!NetworkCommand.ValidateIp(Ip))
          {
            return "Broadcast Ip ungültig";
          }
          break;
        case nameof(Room):
          if (Room == null)
            return "Raum wählen";
          break;
      }
      return string.Empty;
    }


  public abstract class ViewModel : INotifyPropertyChanged, IDataErrorInfo
  {
    private string _ErrorMessage;
    private bool _HasErrors;

    public ViewModel()
    {
      SaveCommand = new RelayCommand(SaveAction);
    }

    public bool HasErrors
    {
      get { return _HasErrors; }
      set
      {
        _HasErrors = value;
        RaisePropertyChanged(nameof(HasErrors));
      }
    }

    public ICommand SaveCommand { get; }

    public Model Model { get; protected set; }

    public string this[string property]
    {
      get
      {
        _ErrorMessage = ValidateProperty(property);
        RaisePropertyChanged(nameof(Error));
        HasErrors = !string.IsNullOrEmpty(Error);
        return Error;
      }
    } 

    public string Error
    {
      get { return _ErrorMessage; }

    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void SaveAction(object obj)
    {
      if (Model != null && Model.Id == 0)
      {
        App.EntityManager.Add(Model);
      }
      App.EntityManager.Save();
    }

    protected virtual string ValidateProperty(string property)
    {
      return string.Empty;
    }

    protected void RaisePropertyChanged(string property)
    {
      PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
  }

  public abstract class ViewModel<T> : ViewModel where T : Model
  {
    protected ViewModel(T model)
    {
      Model = model;
      base.Model = model;
    }

    public new T Model { get; }

    public long Id => Model.Id;
  }

XAML:

    <Label Content="{StaticResource NameString}" />
    <TextBox Text="{Binding Path=Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

    <Label Content="{StaticResource IpString}" />
    <TextBox Text="{Binding Path=Ip,ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

    <Label Content="{StaticResource MacString}" />
    <TextBox Text="{Binding Path=Mac, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

    <Label Content="{StaticResource BroadcastIpString}" />
    <TextBox Text="{Binding Path=BroadcastIp, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

    <Label Content="{StaticResource RoomString}" />
    <ComboBox ItemsSource="{Binding Path=Rooms}" SelectedItem="{Binding Path=Room, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

    <GridSplitter Height="25" />
    <Button x:Name="SaveButton"
            HorizontalAlignment="Right"
            Command="{Binding Path=SaveCommand}"
            Content="{StaticResource SaveIcon}"
            IsEnabled="{Binding Path=CanSave,
                                Converter={StaticResource TrueToFalseConverter},
                                UpdateSourceTrigger=PropertyChanged}" />

在实现ICommand接口的类中调用代码:

var viewModel = parameter as ComputerViewModel;
_Editor = new ComputerEditor();
_Editor.CloseButtonCommand = new RelayCommand(CloseCommand);
_Editor.SaveButton.Click += (s, e) =>
                                  {
                                    App.EntityManager.Add(_Editor.ComputerEditViewModel.Model);
                                    App.EntityManager.Save();
                                    _Editor.IsOpen = false;
                                    (Application.Current.MainWindow.Content as Grid).Effect = null;
                                  };
if (viewModel == null)
{
  _Editor.DataContext = new ComputerEditViewModel(new Computer());
  _Editor.Title = Application.Current.FindResource("ComputerAddString").ToString();
}
else
{
   _Editor.DataContext = new ComputerEditViewModel(viewModel.Model);
   _Editor.Title = Application.Current.FindResource("ComputerEditString").ToString();
}
 OpenChildWindow(_Editor);

我的问题: 当我创建一个没有任何初始值的新实体时,IDataErrorInfo会一直执行,但只有当新实体属性具有有效的初始值时才会显示错误(红色边框和标签)。

Control images

(1)是初始控制状态。第一个文本框(&#39; Name&#39;)具有来自实体构造函数的默认值。所有其他值(文本框)都是空的。 此时,我的验证在我的viewmodel中用于所有文本框/属性,但只有第一个文本框在验证失败时获得红色边框和标签,导致有效的起始值! 对于其他属性,我必须在显示红色边框和标签之前设置有效(初始)值(当验证失败时,属性更改的原因)虽然我检查文本框/属性是否为空。

正如我所说,验证一直在viewmodel中工作,但是当初始值对我的实现有效时,视图只显示红色边框和标签。

希望这个问题不奇怪。 如果有些事情不清楚,请随时提出任何问题

祝你好运 达斯汀

0 个答案:

没有答案