当WPF数据网格选择不可见时,INotifyPropertyChanged的空引用异常

本文关键字:INotifyPropertyChanged 异常 引用 数据 WPF 数据网 网格 选择 | 更新日期: 2023-09-27 18:15:38

我有一个DataGrid控件,用户可以在其中选择多个项目。在选择项目并按下按钮之后,我遍历每个项目并编辑一个属性。当更改此属性时,INotifyPropertyChanged事件将触发。一切都运转得很好。然而,我注意到如果我选择两个或多个项目并滚动,使其中一个项目完全不在视图中,然后按下按钮,程序将崩溃,并在NotifyPropertyChanged()方法中给我一个空引用异常,告诉我PropertyChangedEventHandler为空。如果我从属性的setter中删除NotifyPropertyChanged()调用,代码正常工作,所以现在这就是我正在做的,但为什么会发生这种情况?如果我只选中一个项目,无论滚动位置如何,它都能正常工作。

在实现INotifyPropertyChanged接口的模型类中,我有这些:

    public event PropertyChangedEventHandler PropertyChanged;
    // ...
    public bool IsScheduled
    {
        get { return isScheduled; }
        set { isScheduled = value; NotifyPropertyChanged(self.ToString()); }
    }
    // ...
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

在ViewModel的其他地方,我做了这个触发错误的简单调用:

process.IsScheduled = true;

如果在错误发生时检查所选值列表的值,则所有所选项都将被检测到。似乎当他们不可见时,事件发生了一些事情。

为什么项目在视图中的可见性会影响事件处理程序是否为空?

当WPF数据网格选择不可见时,INotifyPropertyChanged的空引用异常

这样修改代码:

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
}

总是检查null,因为如果没有附加的事件处理程序,它将抛出NullReferenceException除了之外,在引发事件时应该始终使用temp变量,因为任何对象都可以随时为其添加/删除处理程序。

编辑:

根据你的。net框架版本,你还可以改进INotifyPropertyChanged的实现

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "" )
{
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
}

然后通知简单地使用NotifyPropertyChanged();而不显式地传递属性名给方法,因为[CallerMemberName]会自动给你调用者的名字。

这(可能)会减少输入,减少代码中由于拼写错误或属性名称更改而导致的错误的空间。

使用任何事件处理程序的最佳实践是在调用它之前测试是否为null…

if(PropertyChanged != null) this.PropertyChanged....

我也很好奇为什么你会让一个字符串。是否使用空的默认值?

因为处理程序是在WPF中创建的,而不是在代码中显式创建的,所以您无法控制处理程序是否存在-添加检查,您应该可以。

更简单:

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller));

if(PropertyChanged != null) 
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

1行vs 2行