IDataErrorInfo Issue - Initial property values
<p>i have a ViewModel that implements the IDataErrorInfo interface as usual.</p>

<p><strong>Model</strong></p>

<pre><code>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; }
   }
</code></pre>

<p><strong>ViewModel</strong></p>

<pre><code> public class ComputerViewModel : ViewModel&lt;Computer&gt;, 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&lt;RoomViewModel&gt;().FirstOrDefault(r =&gt; 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));
      }
    }

    /// &lt;summary&gt;
    ///   UI indicator when a operation like shutdown, reboot, ping etc. is running
    /// &lt;/summary&gt;
    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&lt;ComputerViewModel&gt;().ToList();

      switch (property)
      {
        case nameof(Name):
          if (string.IsNullOrEmpty(Name))
          {
            return "Bezeichnung erwartet";
          }
          if (computers.Any(c =&gt; 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 =&gt; 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 =&gt; 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 &amp;&amp; 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&lt;T&gt; : ViewModel where T : Model
  {
    protected ViewModel(T model)
    {
      Model = model;
      base.Model = model;
    }

    public new T Model { get; }

    public long Id =&gt; Model.Id;
  }
</code></pre>

<p><strong>XAML:</strong></p>

<pre><code>    &lt;Label Content="{StaticResource NameString}" /&gt;
    &lt;TextBox Text="{Binding Path=Name, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /&gt;

    &lt;Label Content="{StaticResource IpString}" /&gt;
    &lt;TextBox Text="{Binding Path=Ip,ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /&gt;

    &lt;Label Content="{StaticResource MacString}" /&gt;
    &lt;TextBox Text="{Binding Path=Mac, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /&gt;

    &lt;Label Content="{StaticResource BroadcastIpString}" /&gt;
    &lt;TextBox Text="{Binding Path=BroadcastIp, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /&gt;

    &lt;Label Content="{StaticResource RoomString}" /&gt;
    &lt;ComboBox ItemsSource="{Binding Path=Rooms}" SelectedItem="{Binding Path=Room, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" /&gt;

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

<p><strong>Calling code in class that implements ICommand interface:</strong></p>

<pre><code>var viewModel = parameter as ComputerViewModel;
_Editor = new ComputerEditor();
_Editor.CloseButtonCommand = new RelayCommand(CloseCommand);
_Editor.SaveButton.Click += (s, e) =&gt;
                                  {
                                    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);
</code></pre>

<p><strong>My problem:</strong>
When i create a new entity without any initial values the IDataErrorInfo is executed all the time but the error (red border and label) is only shown when the new entity properties has valid initial values.</p>

<p><a href="http://i.stack.imgur.com/Pqusi.png" rel="nofollow">Control images</a></p>

<p>The (1) is the initial controlstate. The first textbox ('Name') has a default value that comes from the entity contructor. All other values (Textboxes) are just empty. 
At this point my validation is working in my viewmodel for all textboxes/properties but only the first textbox get the red border and label when the validation fails, cause of the valid start value!
For the other properties i have to set a valid (initial) value before the red border and label is shown (when validation fails, cause of property change) although i check if the textbox/property is empty.</p>

<p>As i said, the validation is working in the viewmodel all the time but the view only shows the red border and label when the initial value is valid against my implementation.</p>

<p>Hoping this question is not to weird.
Feel free to ask anything if something is just unclear</p>

<p>Best regards
Dustin</p>