【问题标题】:Getting "Key cannot be null" after implementing INotifyPropertyChanged on C# object在 C# 对象上实现 INotifyPropertyChanged 后获取“键不能为空”
【发布时间】:2017-07-28 20:41:35
【问题描述】:

我正在 Visual Studio 2017 中使用 C# 4.5.2 开发 WPF 应用程序。在应用程序中,我有一个自定义对象,该对象被滚动到 ObservableCollection<T> 中以供以后处理。如果/必要时,我希望能够处理这个CollectionChanged 事件。

我为类 (: INotifyPropertyChanged) 添加了适当的装饰,添加了事件和处理程序,并使用接口 PropertyChanged 为我的对象中的每个属性分配了属性:

public class OrderLineItem : INotifyPropertyChanged
{
    private int _lineItemNumber;
    public int LineItemNumber
    {
        get => _lineItemNumber;
        set { _lineItemNumber = value; OnPropertyChanged(); }
    }

    private int _quantity;
    public int Quantity
    {
        get => _quantity;
        set { _quantity = value; OnPropertyChanged(); }

    }

    private string _partNumber;
    public string PartNumber
    {
        get => _partNumber;
        set { _partNumber = value; OnPropertyChanged(); }

    }

    private Hinge _hinged;
    public Hinge Hinging
    {
        get => _hinged;
        set { _hinged = value; OnPropertyChanged(); }
    }

    private Finish _finished;
    public Finish Finished
    {
        get => _finished;
        set { _finished = value; OnPropertyChanged(); }
    }

    private decimal _unitPrice;
    public decimal UnitPrice
    {
        get => _unitPrice;
        set { _unitPrice = value; OnPropertyChanged(); }
    }

    private decimal _modifyPrice;
    public decimal ModifyPrice
    {
        get => _modifyPrice;
        set { _modifyPrice = value; OnPropertyChanged(); }
    }

    private decimal _extendedPrice;
    public decimal ExtendedPrice
    {
        get => _extendedPrice;
        set { _extendedPrice = value; OnPropertyChanged(); }
    }

    private List<string> _modifications;
    public List<string> Modifications
    {
        get => _modifications;
        set { _modifications = value; OnPropertyChanged(); }
    }

    private CabinetType _type;
    public CabinetType Type
    {
        get => _type;
        set { _type = value; OnPropertyChanged(); }
    }

    private string _display;
    public string Display
    {
        get => _display;
        set { _display = value; OnPropertyChanged(); }
    }

    public enum Hinge { None = 0, L, R, BD }
    public enum Finish { None = 0, L, R, B }

    public OrderLineItem()
    {
        LineItemNumber = -1;
        Quantity = -1;
        PartNumber = string.Empty;
        Hinging = Hinge.None;
        Finished = Finish.None;
        UnitPrice = 0.00m;
        ModifyPrice = 0.00m;
        ExtendedPrice = 0.00m;
        Modifications = new List<string>();
        Type = CabinetType.None;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

在我的MainWindow.xaml.cs 文件中,我将.CollectionChanged 处理程序添加到我的ObservableCollection&lt;T&gt;.PropertyChanged 处理程序到我的对象:

private void AddedItemsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (OrderLineItem newItem in e.NewItems)
        {
            _addedItems.Add(newItem);
            newItem.PropertyChanged += OnItemPropertyChanged;
        }
    }

    if (e.OldItems != null)
    {
        foreach (OrderLineItem oldItem in e.OldItems)
        {
            _addedItems.Add(oldItem);
            oldItem.PropertyChanged -= OnItemPropertyChanged;
        }
    }
}

private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    OrderLineItem item = sender as OrderLineItem;
    if (item != null) _addedItems.Add(item);
}

每当我将一个项目添加到集合中时,我都会向它添加 PropertyChanged 处理程序:

...

item.PropertyChanged += ItemOnPropertyChanged;

...

此集合通过 .ItemsSource 属性显示在 DataGrid 中。

此问题标题中的问题发生在 实施 INotifyPropertyChanged 及其相关方法/接口等之后。

我能够获得的堆栈跟踪没有为我提供任何有用的信息(行号、文件、方法等)来尝试调试它。我确实启用了所有调试选项,以确保我没有忽略任何潜在的异常。 Here is a pastebin of the exception。指示的行号是这样的:

 AppDomain.CurrentDomain.UnhandledException += 
  (sender, args) => throw new Exception("Unhandled exception: " + args.ExceptionObject);

如果我没有这行,或者注释掉this is a pastebin of the exception I get instead

除了实现CollectionChanged事件之外,我应该如何继续尝试解决这个问题?

【问题讨论】:

  • 只是一件小事——你的代码有newItem.PropertyChanged += OnItemPropertyChanged;,但事件处理程序通常没有名称中的On部分——约定是以On开头的方法是在那里引发事件,而不是处理它们。
  • @Enigmativity 很好,我相信 ReSharper 可能已经自动命名了该方法。
  • 您能否发布您的 DataGrid 的 XAML 源代码?我在类似情况下遇到了同样的异常,通过显式设置绑定的 Path 属性(例如,将 Binding="{Binding (a:B.C)}" 更改为 Binding="{Binding Path=(a:B.C)} ”)。我不确定为什么会这样。
  • @Enigmativity,当事件处理程序以“On”开头命名时,文档中有很多示例。就个人而言,为了避免混淆,我尽量遵守规则:名称处理程序以“On”开头,创建事件的方法以“Raise”开头。我为代表使用结尾的“处理程序”。
  • @EldHasp - 你说得对,很多人错误地执行了约定。

标签: c# wpf observablelist


【解决方案1】:

似乎与 INotifyPropertyChanged 和 Binding 规则有关系,但我不知道是哪一个。

我遇到了同样的问题:在 PropertyGrid 项目上实现 INotifyPropertyChanged 触发了 Key cannot be null 绑定错误。顺便说一句,这是我见过的最无用和最随机的错误日志之一。

Cannot save value from target back to source.
BindingExpression:[info on an unrelated parent binding...]
ArgumentNullException:'System.ArgumentNullException: Key cannot be null.

一段时间后,我发现旧 wpf 版本中有奇怪的绑定行为,在绑定中添加 Path= 可以修复它,但事实并非如此。

我实际上在代码隐藏中有一个绑定,如下所示:

void GetBinding(PropertyItem propertyItem)
{
  return new Binding($"({propertyItem.PropertyName})")
  {
    //[Source, Mode, etc...] 
  }
}

并且代码适用于属性和附加属性,但在此类上实现属性通知程序后立即停止工作。也许触发了更严格的规则并将我的属性标记为不是“附加”属性,但它之前在没有接口的情况下工作。

所以,我删除了括号,它现在可以工作了。

  return new Binding($"{propertyItem.PropertyName}")

【讨论】:

    【解决方案2】:

    查看您的异常,问题似乎与从您的 HybridDictionary 中搜索空键有关。

    我猜测 INotifyPropertyChanged 实现只是触发了这个 HybridDictionary[null] 查找,与根本问题无关。

    在更高的层次上,这似乎是 VS 调试器应该直接跳转到的东西,所以这看起来很奇怪,我建议在你的环境中进行挖掘以确保调试正常工作。

    【讨论】:

      猜你喜欢
      • 2011-11-09
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 1970-01-01
      • 2020-08-22
      • 2017-08-06
      • 1970-01-01
      • 2017-08-18
      相关资源
      最近更新 更多