在任何布局控件的Children上获取CollectionChanged事件?

时间:2015-03-20 04:41:49

标签: c# wpf layout children

如何从任何LayoutControl的子项中获取ItemAdded,ItemRemoved通知?

假设我们有Grid控件。如果我在Grid中添加新的TextBlock控件,那么它应该通过添加的项目通知我。如果已删除,则应通知我已从Children's (UIElementCollection)删除的项目,例如ObservableCollection

这可能吗?

3 个答案:

答案 0 :(得分:6)

不确定为什么要这样做,但我想你可以扩展Grid面板并覆盖OnVisualChildrenChanged protected方法来引发一个事件:

public class ObservableGrid : Grid
{
    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);

        if (VisualChildrenChanged != null)
            VisualChildrenChanged(this, new VisualChildrenChangedEventArgs(visualAdded, visualRemoved));
    }

    public event EventHandler<VisualChildrenChangedEventArgs> VisualChildrenChanged;
}

public class VisualChildrenChangedEventArgs : EventArgs
{
    public VisualChildrenChangedEventArgs(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        VisualAdded = visualAdded;
        VisualRemoved = visualRemoved;
    }

    public DependencyObject VisualAdded { get; private set; }
    public DependencyObject VisualRemoved { get; private set; }
}

答案 1 :(得分:1)

如果您能够创建自己的Panel,则可以覆盖一些虚拟方法以在其子类中实现INotifyCollectionChanged。但这需要您自己重新实现布局算法。

public class ObservablePanel : Panel, INotifyCollectionChanged
{
    public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { };

    protected override UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
    {
        var oldObservableCollection = InternalChildren as INotifyCollectionChanged;
        if (oldObservableCollection != null)
            oldObservableCollection.CollectionChanged -= OnChildrenChanged;

        var collection = new ObservableUIElementCollection(this, logicalParent);
        collection.CollectionChanged += OnChildrenChanged;

        return collection;
    }

    private void OnChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        CollectionChanged(sender, e);
    }
}

public class ObservableUIElementCollection : UIElementCollection, INotifyCollectionChanged
{
    public ObservableUIElementCollection(UIElement visualParent, FrameworkElement logicalParent)
        : base(visualParent, logicalParent)
    {
    }

    public event NotifyCollectionChangedEventHandler CollectionChanged = delegate { };

    public override int Add(UIElement element)
    {
        var i = base.Add(element);

        IList newItems = new List<UIElement> { element };
        IList oldItems = new List<UIElement>();
        CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, newItems, oldItems));

        return i;
    }

    ...
}

如果您知道,您只使用Grid,则可以将其子类化。但我没有看到一种方法将INotifyCollectionChanged一次性添加到PresentationFramework中存在的所有面板。

答案 2 :(得分:0)

由于您正在尝试构建自己的Collection控件,因此您应该从Microsoft的ItemsControl实现中获取灵感。 您应该检查的方法是:

private void CreateItemCollectionAndGenerator()

private void OnItemCollectionChanged1(object sender, NotifyCollectionChangedEventArgs e)

internal void AdjustItemInfos(NotifyCollectionChangedEventArgs e, IEnumerable list)

这个课程通常是一个很好的研究,以最通用的方式理解实现自己的ItemsCollection的思考过程。