Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DataGridRow错误指示器不使用INotifyDataErrorInfo_C#_.net_Wpf_.net 4.5_Inotifydataerrorinfo - Fatal编程技术网

C# DataGridRow错误指示器不使用INotifyDataErrorInfo

C# DataGridRow错误指示器不使用INotifyDataErrorInfo,c#,.net,wpf,.net-4.5,inotifydataerrorinfo,C#,.net,Wpf,.net 4.5,Inotifydataerrorinfo,我正在尝试更新ViewModel以使用INotifyDataErrorInfo而不是IDataErrorInfo,并遇到以下问题: 当前编辑字段的验证似乎工作正常,但行级错误指示器直到我结束对字段的编辑并出现错误,然后开始重新编辑它时才会出现。之后,错误指示器消失,事件修复后验证错误 换句话说: 第一次编辑行时,文本框轮廓正确地变为红色,但行指示器没有出现。重新编辑行会导致显示行指示符。修复验证错误会导致字段轮廓消失,但留下感叹号 请注意,IDataErrorInfo似乎工作正常。我遇到麻烦的是

我正在尝试更新ViewModel以使用INotifyDataErrorInfo而不是IDataErrorInfo,并遇到以下问题:

当前编辑字段的验证似乎工作正常,但行级错误指示器直到我结束对字段的编辑并出现错误,然后开始重新编辑它时才会出现。之后,错误指示器消失,事件修复后验证错误

换句话说: 第一次编辑行时,文本框轮廓正确地变为红色,但行指示器没有出现。重新编辑行会导致显示行指示符。修复验证错误会导致字段轮廓消失,但留下感叹号

请注意,IDataErrorInfo似乎工作正常。我遇到麻烦的是INotifyDataErrorInfo

解决方案的一半:将绑定更改为双向会使行指示符正确显示,但它仍然不想消失

以下是观点:

<DataGrid ItemsSource="{Binding Items, ValidatesOnNotifyDataErrors=True}" AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name, ValidatesOnNotifyDataErrors=True,Mode=TwoWay}" />
    </DataGrid.Columns>
</DataGrid>

下面是视图模型:

public class Item : INotifyDataErrorInfo, INotifyPropertyChanged
{
    Dictionary<string, IEnumerable<string>> _errors = new Dictionary<string,IEnumerable<string>>();
    string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                ValidateProperty("Name", value);
                _name = value;
                RaisePropertyChanged("Name");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void RaisePropertyChanged(string p)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(p));
    }

    private void ValidateProperty(string p, object value)
    {
        if (p == "Name")
        {
            if (string.IsNullOrWhiteSpace((string)value))
                _errors["Name"] = new[] { "Name is required." };
            else
                _errors["Name"] = new string[0];
        }

        if (ErrorsChanged != null)
            ErrorsChanged(this, new DataErrorsChangedEventArgs(null));
    }

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public System.Collections.IEnumerable GetErrors(string propertyName)
    {
        if (string.IsNullOrEmpty(propertyName))
            return _errors.Values.SelectMany(es2 => es2);

        IEnumerable<string> es;
        _errors.TryGetValue(propertyName ?? "", out es);
        return es;
    }

    public bool HasErrors
    {
        get
        {
            var e = _errors.Values.Any(es => es.Any());
            return e;
        }
    }
}
公共类项:INotifyDataErrorInfo,INotifyPropertyChanged
{
字典_errors=新字典();
字符串\u名称;
公共字符串名
{
获取{return\u name;}
设置
{
如果(_name!=值)
{
ValidateProperty(“名称”,值);
_名称=值;
RaiseProperty变更(“名称”);
}
}
}
公共事件属性更改事件处理程序属性更改;
私有void raiseProperty已更改(字符串p)
{
if(PropertyChanged!=null)
房地产变更(这是新的房地产变更发展(p));
}
私有void ValidateProperty(字符串p,对象值)
{
如果(p==“名称”)
{
if(string.IsNullOrWhiteSpace((string)值))
_错误[“名称”]=新[]{“名称是必需的。”};
其他的
_错误[“名称”]=新字符串[0];
}
if(ErrorsChanged!=null)
ErrorsChanged(这是新数据ErrorSchangedEventArgs(null));
}
公共事件事件处理程序错误更改;
public System.Collections.IEnumerable GetErrors(字符串propertyName)
{
if(string.IsNullOrEmpty(propertyName))
返回_errors.Values.SelectMany(es2=>es2);
可数名词;
_错误。TryGetValue(propertyName??,输出es);
返回es;
}
公共布尔错误
{
得到
{
var e=_errors.Values.Any(es=>es.Any());
返回e;
}
}
}
似乎这个问题已经被问过了,但被原作者删除了: 原始问题的副本,但此处没有答案:

编辑:

以下是我的测试源代码:

以下是我提交给MS的报告:

我知道我以前告诉过您将绑定模式设置为双向,这是正确的,不过您还必须小心如何定义验证规则。如果你介意在这两者之间找到平衡,一切都会很好

这里有一个例子,一切都很好。正如我提到的,我不能认同你的例子,我遗漏了一些细节,以便能够重现你的问题,因此这里是一个简短的例子

<Grid>
    <DataGrid
       CanUserAddRows="True"
       AutoGenerateColumns="False"  
       ItemsSource="{Binding Pricelist}" >
       <DataGrid.Columns>
            <DataGridTextColumn
               Header="Price" 
               Width="60" 
               Binding="{Binding Price, 
                         Mode=TwoWay, 
                         UpdateSourceTrigger=PropertyChanged,
                         ValidatesOnDataErrors=True}">
            </DataGridTextColumn>
       </DataGrid.Columns>
    </DataGrid>
</Grid>
这是实现INotifyDataErrorInfo的类

public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public Owner()
   {
      FailedRules = new Dictionary<string, string>();
   }

   private Dictionary<string, string> FailedRules
   {
      get;
      set;
   }

   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   public IEnumerable GetErrors(string propertyName)
   {
      if (FailedRules.ContainsKey(propertyName))
         return FailedRules[propertyName];
      else
         return FailedRules.Values;
   }

   internal void FireValidation()
   {
      if (lastName.Length > 20)
      {
         if (!FailedRules.ContainsKey("LastName"))
            FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
      }
      else
      {
         if (FailedRules.ContainsKey("LastName"))
            FailedRules.Remove("LastName");
      }

      NotifyErrorsChanged("LastName");
   }

   public bool HasErrors
   {
      get { return FailedRules.Count > 0; }
   }

   private void NotifyErrorsChanged(string propertyName)
   {
      if (ErrorsChanged != null)
         ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
   }
}
公共类所有者:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共所有者()
{
FailedRules=新字典();
}
专用字典故障规则
{
得到;
设置
}
公共事件事件处理程序错误更改;
公共IEnumerable GetErrors(字符串propertyName)
{
if(FailedRules.ContainsKey(propertyName))
返回失败的规则[propertyName];
其他的
返回FailedRules.值;
}
内部无效验证()
{
如果(lastName.Length>20)
{
如果(!FailedRules.ContainsKey(“LastName”))
FailedRules.Add(“姓氏”,“姓氏不能超过20个字符”);
}
其他的
{
if(FailedRules.ContainsKey(“姓氏”))
失败规则。删除(“姓氏”);
}
NOTIFYERRSCHANGED(“姓氏”);
}
公共布尔错误
{
获取{return FailedRules.Count>0;}
}
私有void NOTIFYERRSCHANGED(字符串属性名称)
{
if(ErrorsChanged!=null)
ErrorsChanged(这是新数据ErrorSchangedEventArgs(propertyName));
}
}

我知道我以前告诉过您将绑定模式设置为双向,这是正确的,不过您还必须小心如何定义验证规则。如果你介意在这两者之间找到平衡,一切都会很好

这里有一个例子,一切都很好。正如我提到的,我不能认同你的例子,我遗漏了一些细节,以便能够重现你的问题,因此这里是一个简短的例子

<Grid>
    <DataGrid
       CanUserAddRows="True"
       AutoGenerateColumns="False"  
       ItemsSource="{Binding Pricelist}" >
       <DataGrid.Columns>
            <DataGridTextColumn
               Header="Price" 
               Width="60" 
               Binding="{Binding Price, 
                         Mode=TwoWay, 
                         UpdateSourceTrigger=PropertyChanged,
                         ValidatesOnDataErrors=True}">
            </DataGridTextColumn>
       </DataGrid.Columns>
    </DataGrid>
</Grid>
这是实现INotifyDataErrorInfo的类

public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public Owner()
   {
      FailedRules = new Dictionary<string, string>();
   }

   private Dictionary<string, string> FailedRules
   {
      get;
      set;
   }

   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   public IEnumerable GetErrors(string propertyName)
   {
      if (FailedRules.ContainsKey(propertyName))
         return FailedRules[propertyName];
      else
         return FailedRules.Values;
   }

   internal void FireValidation()
   {
      if (lastName.Length > 20)
      {
         if (!FailedRules.ContainsKey("LastName"))
            FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
      }
      else
      {
         if (FailedRules.ContainsKey("LastName"))
            FailedRules.Remove("LastName");
      }

      NotifyErrorsChanged("LastName");
   }

   public bool HasErrors
   {
      get { return FailedRules.Count > 0; }
   }

   private void NotifyErrorsChanged(string propertyName)
   {
      if (ErrorsChanged != null)
         ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
   }
}
公共类所有者:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共所有者()
{
FailedRules=新字典();
}
专用字典故障规则
{
得到;
设置
}
公共事件事件处理程序错误更改;
公共IEnumerable GetErrors(字符串propertyName)
{
if(FailedRules.ContainsKey(propertyName))
返回失败的规则[propertyName];
其他的
返回FailedRules.值;
}
内部无效验证()
{
如果(lastName.Length>20)
{
如果(!FailedRules.ContainsKey(“LastName”))
FailedRules.Add(“姓氏”,“姓氏不能超过20个字符”);
}
其他的
{
if(FailedRules.ContainsKey(“姓氏”))
失败规则。删除(“姓氏”);
}
NOTIFYERRSCHANGED(“姓氏”);
}
公共布尔错误
{
得到
public class Owner : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public Owner()
   {
      FailedRules = new Dictionary<string, string>();
   }

   private Dictionary<string, string> FailedRules
   {
      get;
      set;
   }

   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   public IEnumerable GetErrors(string propertyName)
   {
      if (FailedRules.ContainsKey(propertyName))
         return FailedRules[propertyName];
      else
         return FailedRules.Values;
   }

   internal void FireValidation()
   {
      if (lastName.Length > 20)
      {
         if (!FailedRules.ContainsKey("LastName"))
            FailedRules.Add("LastName", "Last name cannot have more than 20 characters");
      }
      else
      {
         if (FailedRules.ContainsKey("LastName"))
            FailedRules.Remove("LastName");
      }

      NotifyErrorsChanged("LastName");
   }

   public bool HasErrors
   {
      get { return FailedRules.Count > 0; }
   }

   private void NotifyErrorsChanged(string propertyName)
   {
      if (ErrorsChanged != null)
         ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
   }
}