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