如果可观察集合中对象的属性发生更改,则在XAML中调用转换器

时间:2012-09-27 11:59:53

标签: c# .net wpf xaml observablecollection

我有一个转换器接受ObservableCollection作为参数,并且我想在集合中任何项目的特定属性发生更改时重新评估它

例如:假设我已经使用转换器将标签绑定到Person个对象的集合。转换器的工作是计算列表中女性的人数,并返回"有效"为1女性或"接受"对于2.我希望在任何Gender对象的Person属性发生更改时,都可以再次调用转换器。

我该如何做到这一点?

2 个答案:

答案 0 :(得分: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。

答案 1 :(得分:0)

只有在集合中添加或删除项目时才会抛出CollectionChanged事件(而不是在集合中的项目发生更改时)。因此,在更改项目时不会调用转换器。

一种选择:
在Gender属性集中包含用于评估集合的逻辑,并设置将标签绑定到的字符串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);
        };
    }
}