开发者

VisualCollection and ContentPropertyAttribute in XAML

I want to write a custom FrameworkElement which host Visuals. My first attempt was to create an instance of ContainerVisual and write a wrapper property for ContainerVisual.Children and then set it as ContentProperty so I can and Visuals via XAML. But VisualCollectio开发者_如何学Gon does only implement ICollection and not IList or any supported interface and VisualCollection is selead so I can't implement IList on my own.

How can I hostvisuals and let them add declaratively using XAML?


Okay, long time ago but here is the solution I found that time back...

The Collection: Note the hack comments.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using System.Collections.ObjectModel;
using WPF.Controls.Primitives;

namespace WPF.Controls.Core
{
    public class PrimitiveCollection : ObservableCollection<Primitive>
    {
        protected PrimitiveContainerVisual _owner;

        public PrimitiveCollection(PrimitiveContainerVisual owner)
            : base()
        {
            if (owner == null)
                throw new ArgumentNullException("owner");

            _owner = owner;
        }

        protected override void ClearItems()
        {
            foreach (var item in this)
            {
                item.IsDirtyChanged -= new IsDirtyChangedHandler(item_IsDirtyChanged);
                _owner.InternalRemoveVisualChild(item);
            }

            base.ClearItems();
        }

        protected override void InsertItem(int index, Primitive item)
        {
            if (item != null && item.Parent != null)
                throw new ArgumentNullException("Visual has parent");

            item.IsDirtyChanged += new IsDirtyChangedHandler(item_IsDirtyChanged);
            _owner.InternalAddVisualChild(item);

            base.InsertItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            Primitive item = this[index];

            item.IsDirtyChanged -= new IsDirtyChangedHandler(item_IsDirtyChanged);
            _owner.InternalRemoveVisualChild(item);
            base.RemoveItem(index);
        }

        protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
        }

        void item_IsDirtyChanged(object sender, PrimitiveChangedEventArgs e)
        {
            if(e.IsDirty)
                _owner.RequestRedraw();
        }
    }
}

And the Control which you can use in XAML

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media;
using WPF.Controls.Primitives;
using System.Windows;
using System.Reflection;

namespace WPF.Controls.Core
{
    public class PrimitiveContainerVisual : Visual
    {
        private PrimitiveCollection _primitives;
        private PropertyInfo _contentBoundsPropInfo;
        private PropertyInfo _descendantBoundsPropInfo;

        public PrimitiveCollection Children
        {
            get { return _primitives; }
            set { _primitives = value; }
        }

        public Rect ContentBounds
        {
            // HACK access internal property of Visual
            get { return (Rect)_contentBoundsPropInfo.GetValue(this, null); }
        }

        public Rect DescendantBounds
        {
            // HACK access internal property of Visual
            get { return (Rect)_descendantBoundsPropInfo.GetValue(this, null); }
        }

        public PrimitiveContainerVisual()
        {
            _primitives = new PrimitiveCollection(this);
            Type thisType = this.GetType();
            BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
            _contentBoundsPropInfo = thisType.GetProperty("VisualContentBounds", flags);
            _descendantBoundsPropInfo = thisType.GetProperty("VisualDescendantBounds", flags);
        }

        internal void InternalAddVisualChild(Primitive prim)
        {
            this.AddVisualChild(prim);
        }

        internal void InternalRemoveVisualChild(Primitive prim)
        {
            this.RemoveVisualChild(prim);
        }

        public bool RequestRedraw()
        {
            UIElement uiParent = VisualParent as UIElement;

            if (uiParent != null)
            {
                uiParent.InvalidateVisual();
                return true;
            }
            else
                return false;
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜