1

我有一个接受 aObservableCollection作为参数的转换器,每当集合中任何项目的特定属性发生变化时,我都想重新评估它

例如:假设我已经Person使用转换器将标签绑定到对象集合。转换器的工作是计算列表中女性的人数,并为 1 位女性返回“有效”或为 2 位女性返回“接受”。我希望转换器在任何时候再次调用Gender任何Person对象上的属性变了。

我怎样才能做到这一点?

4

2 回答 2

3

如果您在 WPF 上玩的时间足够长,那么您最终会遇到的经典问题。

我尝试了各种解决方案,但效果最好的一个是使用 BindingList ,如下所示:

public class WorldViewModel : INotifyPropertyChanged
{
   private BindingList<Person> m_People;
   public BindingList<Person> People
   {
      get { return m_People; }
      set
      {
         if(value != m_People)
         {
            m_People = value;
            if(m_People != null)
            {
               m_People.ListChanged += delegate(object sender, ListChangedEventArgs args)
               {
                  OnPeopleListChanged(this);
               };
            }
            RaisePropertyChanged("People");
         }
      }
   }

   private static void OnPeopleListChanged(WorldViewModel vm)
   {
      vm.RaisePropertyChanged("People");
   }

   public event PropertyChangedEventHandler PropertyChanged;
   void RaisePropertyChanged(String prop)
   {
      PropertyChangedEventHandler handler = this.PropertyChanged;
      if (handler != null)
      {
          handler(this, new PropertyChangedEventArgs(prop));
      }
   }
}

然后就像使用 ObservableCollection 一样绑定到 People 集合,除了绑定将在其项目中的任何属性更改时重新评估。

另外,请注意 OnPeopleListChanged 是静态的,因此没有内存泄漏。

Person 应该实现 INotifyPropertyChanged。

于 2012-09-27T13:38:40.207 回答
0

仅当从集合中添加或删除项目时(而不是更改集合中的项目),才会引发 CollectionChanged 事件。因此,更改项目时不会调用转换器。

一种选择:
在 Gender Property Set 中包含评估集合的逻辑并设置您将标签绑定到的字符串 Property。

写了狒狒答案的通用版本

public class ObservalbeList<T>: INotifyPropertyChanged
{
    private BindingList<T> ts = new BindingList<T>();

    public event PropertyChangedEventHandler PropertyChanged;

    // This method is called by the Set accessor of each property. 
    // The CallerMemberName attribute that is applied to the optional propertyName 
    // parameter causes the property name of the caller to be substituted as an argument. 
    private void NotifyPropertyChanged( String propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public BindingList<T> Ts
    {
        get { return ts; }
        set
        {
            if (value != ts)
            {
                Ts = value;
                if (Ts != null)
                {
                    ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
                    {
                        OnListChanged(this);
                    };
                }
                NotifyPropertyChanged("Ts");
            }
        }
    }

    private static void OnListChanged(ObservalbeList<T> vm)
    {
        vm.NotifyPropertyChanged("Ts");
    }

    public ObservalbeList()
    {
        ts.ListChanged += delegate(object sender, ListChangedEventArgs args)
        {
            OnListChanged(this);
        };
    }
}
于 2012-09-27T12:16:35.830 回答