【问题标题】:Missing PropertyChanged event when BindingList elements has properties changedBindingList 元素的属性发生更改时缺少 PropertyChanged 事件
【发布时间】:2011-11-28 10:20:12
【问题描述】:

我有一个类ViewModel,它有一个MyList 类型为BindingList<Foo> 的属性。

ViewModel 实现 INotifyPropertyChanged

Foo 具有属性FooProp

Foo 实现INotifyPropertyChanged

ViewModel 有这个属性:

public bool IsButtonEnabled
  {
    get
    {
      return MyList.Any(x=> x.FooProp!=null);
   }
}

我有一个带有按钮的视图。按钮的 Enabled 属性绑定到 IsButtonEnabled

但是当MyList 的元素设置为FooProp 时,按钮不会启用。我注意到 ViewModel 不会在这里触发 PropertyChanged 事件。为什么不?我应该如何让视图模型注意到它的 IsButtonEnabled 属性实际上已经改变了?

【问题讨论】:

  • 你能把剩下的代码贴出来吗?所有的 FooProps 都应该不是 null 还是只有一个?

标签: c# .net data-binding collections


【解决方案1】:

已编辑:没有注意到这是一个 getter 而不是 setter。重点还是一样的。简单地实现INotifyPropertyChanged 接口并不会自动添加您需要的所有内容。您需要创建触发事件的方法(如下)。然后,您需要在所有属性的 SETTER 中调用该方法。

您不应该自己触发 PropertyChanged 事件吗?

public bool IsButtonEnabled
{
    get
    {
        return MyList.Any(x=> x.FooProp!=null);

        // assuming you named the method this
        OnPropertyChanged("IsButtonEnabled");
    }
}

INotifyPropertyChanged 界面仅为您创建事件。您需要自己从 ViewModel 触发事件。

如果您尚未创建该方法,则此方法通常可以使用。当 ViewModel 的属性发生变化时,您将显式调用此方法。

private void OnPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

【讨论】:

  • 在那个 getter 中触发事件是没有意义的 ;)
  • 你是对的。甚至没有注意到它是 getter 而不是 setter。
【解决方案2】:

ViewModel 不会在此处触发任何 PropertyChanged,因为 ViewModel 的属性没有更改。实际更改的属性 FooProp 是 Foo 类的属性,而不是 ViewModel。

为了启用/禁用基于IsButtonEnabled 功能的按钮,您必须跟踪 MyList 的所有元素并查看是否进行了任何更改。因此,以下应该有效:

public class Foo : INotifyPropertyChanged
{
    void OnPropertyChanged(string propertyName) { /* ... */ }
    public object FooProp 
    { 
        get { return _obj; }
        set 
        {
            _obj = value;
            OnPropertyChanged("FooProp");
        }
    }
}

public class ViewModel : INotifyPropertyChanged
{
    void OnPropertyChanged(string propertyName) { /* ... */ }

    private List<Foo> _myList;
    public List<Foo> MyList 
    { 
        get { return _myList; }
        set 
        {
            _myList = value;
            foreach(var item in _myList) 
            {
                HandleItem(item);
            }
        }
    }

    void AddItem(Foo item) 
    {
        MyList.Add(item);
        HandleItem(item);
    }
    void HandleItem(Foo item) 
    {
        item.PropertyChanged += (s, e) =>
        {
            if(e.PropertyName == "FooProp")
        };
    }
    void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(e.PropertyName == "FooProp") OnPropertyChanged("IsButtonEnabled");
    }
    public bool IsButtonEnabled
    {
        get
        {
          return MyList.Any(x=> x.FooProp!=null);
        }
    }
}

请注意,在这种情况下,您需要使用 ViewModel.AddItem() 来将项目添加到 MyList(您可以使用 MyList.Add(),但它不会触发正确的通知)。

此外,上面的代码也不是最好的方法 - 它只是说明您的案例应该如何工作。在您了解您可能会将 List 替换为 ObservableCollection 以便能够自动跟踪/处理列表中的项目。

【讨论】:

    猜你喜欢
    • 2011-02-08
    • 1970-01-01
    • 1970-01-01
    • 2014-10-04
    • 2014-04-08
    • 1970-01-01
    • 2019-03-26
    • 2011-01-26
    • 1970-01-01
    相关资源
    最近更新 更多