2

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

1 に答える 1

1

質問に動作コードを投稿すると、私はそれを理解することができました。私の DependencyProperty は、オーナー タイプとして CollectionViewSourceItemFilter の代わりに ItemFilterBehavior を使用しました。

于 2012-05-06T04:48:06.907 に答える