BindingList 元素属性更改时缺少 PropertyChanged 事件

发布于 2024-12-07 09:51:34 字数 688 浏览 0 评论 0原文

我有一个类 ViewModel,它具有 BindingList 类型的属性 MyList

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 属性实际上已更改?

I have a class ViewModel that has a property MyList of type BindingList<Foo>.

ViewModel implements INotifyPropertyChanged.

Foo has the property FooProp.

Foo implements INotifyPropertyChanged

ViewModel has this property:

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

I have a view with a button. The Enabled property of the button is bound to IsButtonEnabled.

But the button doesn't get enabled when an element of MyList has it's FooProp set. I've noticed that ViewModel doesn't fire a PropertyChanged event here. Why not? And how should I go about for the view model to notice that it's IsButtonEnabled property actually has changed?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

南街女流氓 2024-12-14 09:51:34

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<>能够自动跟踪/处理列表中的项目。

ViewModel will not fire any PropertyChanged here because ViewModel's properties are not changed. The actual property that was changed FooProp which is a property of class Foo, not ViewModel.

In order to enable/disable the button based on the IsButtonEnabled functionality you will have to track all the elements of MyList and see if any changes are done. So, the following should work:

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);
        }
    }
}

Note that in this case you need to use ViewModel.AddItem() in order to add an item to MyList (you can use MyList.Add(), but it will not fire the correct notifications then).

Also the code above is not the best way to do it - it is just an illustration of how your case should work. After you understand that you are probably going to replace the List<> to ObservableCollection<> to be able to track/handle items in your list automatically.

养猫人 2024-12-14 09:51:34

编辑:没有注意到这是一个 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));
}

EDITED: Didn't notice that this was a getter and not a setter. The point is still the same. Simply implementing the INotifyPropertyChanged interface doesn't automatically add everything you need. You need to create the method(below) that fires the event. Then you need to call that method in the SETTER of all of your properties.

Shouldn't you fire the PropertyChanged event yourself?

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

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

The INotifyPropertyChanged interface only creates the event for you. You need to fire the event from the ViewModel yourself.

If you haven't already created the method, this one normally works. You would call this method explicitly when a property of the ViewModel changes.

private void OnPropertyChanged(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文