2012-05-05 32 views
2

我想添加一個附加的行爲到一個CollectionViewSource,以便我可以在我的視圖模型在XAML中提供一個過濾器謂詞屬性。如何將附加的行爲添加到CollectionViewSource中?

的XAML如下所示:

<DataGrid ItemsSource="{Binding}"> 
    <DataGrid.DataContext> 
     <CollectionViewSource Source="{Binding Path=Items}" 
       acb:CollectionViewSourceItemFilter.ItemFilter="{Binding Path=ItemFilter}" /> 
    </DataGrid.DataContext> 
</DataGrid> 

不過,我得到一個錯誤:

A 'Binding' cannot be set on the 'SetItemFilter' property of type 
'CollectionViewSource'. A 'Binding' can only be set on a DependencyProperty of a 
DependencyObject. 

CollectionViewSource似乎是一個DependencyObject的。我不確定我做錯了什麼。

下面是行爲的代碼:

public static class CollectionViewSourceItemFilter 
{ 
    /// <summary> 
    /// Gets the property value. 
    /// </summary> 
    public static Predicate<object> GetItemFilter(CollectionViewSource collectionViewSource) 
    { 
     return (Predicate<object>)collectionViewSource.GetValue(ItemFilter); 
    } 

    /// <summary> 
    /// Sets the property value. 
    /// </summary> 
    public static void SetItemFilter(CollectionViewSource collectionViewSource, Predicate<object> value) 
    { 
     collectionViewSource.SetValue(ItemFilter, value); 
    } 

    /// <summary> 
    /// The ItemFilter dependency property. 
    /// </summary> 
    public static readonly DependencyProperty ItemFilter = 
     DependencyProperty.RegisterAttached(
     "ItemFilter", 
     typeof(Predicate<object>), 
     typeof(ItemFilterBehavior), 
     new UIPropertyMetadata(null, OnItemFilterChanged)); 

    private static void OnItemFilterChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
    { 
     CollectionViewSource collectionViewSource = depObj as CollectionViewSource; 
     if (collectionViewSource == null) 
      return; 

     if (!Equals(e.NewValue, e.OldValue)) 
     { 
      var newFilter = (Predicate<object>)e.NewValue; 

      // Remove any previous filter. 
      ItemFilterBehavior oldBehavior; 
      if (behaviors.TryGetValue(collectionViewSource, out oldBehavior)) 
      { 
       oldBehavior.Unregister(); 
       behaviors.Remove(collectionViewSource); 
      } 

      if (newFilter != null) 
       behaviors.Add(collectionViewSource, new ItemFilterBehavior(collectionViewSource, newFilter)); 
     } 
    } 

    private class ItemFilterBehavior 
    { 
     public ItemFilterBehavior(CollectionViewSource collectionViewSource, Predicate<object> filter) 
     { 
      _collectionViewSource = collectionViewSource; 
      _filter = filter; 
      _collectionViewSource.Filter += collectionViewSource_Filter; 
     } 

     void collectionViewSource_Filter(object sender, FilterEventArgs e) 
     { 
      e.Accepted = _filter(e.Item); 
     } 

     public void Unregister() 
     { 
      _collectionViewSource.Filter -= collectionViewSource_Filter; 
     } 

     private readonly CollectionViewSource _collectionViewSource; 
     private readonly Predicate<object> _filter; 
    } 

    private static readonly IDictionary<CollectionViewSource, ItemFilterBehavior> behaviors = new ConcurrentDictionary<CollectionViewSource, ItemFilterBehavior>(); 
} 
+0

試試這個:'public static readonly DependencyProperty ItemFilterProperty = ...' –

+1

感謝您發佈您的問題。這讓我意識到,有人在那裏試圖做同樣的事情,我是。 – jpierson

+0

@jpierson後日期週年upvote。所有關於在MVVM中過濾CollectionViewSource的討論,你都會認爲這篇文章會有更多的關注。 – TaterJuice

回答

1

發佈的問題行爲的代碼導致我看着辦吧。我的DependencyProperty使用ItemFilterBehavior而不是CollectionViewSourceItemFilter作爲所有者類型。