VisualCollection и ContentPropertyAttribute в XAML - PullRequest
0 голосов
/ 27 сентября 2010

Я хочу написать собственный FrameworkElement, в котором размещаются визуалы. Моей первой попыткой было создать экземпляр ContainerVisual и написать свойство-обертку для ContainerVisual.Children, а затем установить его как ContentProperty, чтобы я мог и Visuals через XAML. Но VisualCollection реализует только ICollection, а не IList или любой другой поддерживаемый интерфейс, и VisualCollection является селективной, поэтому я не могу реализовать IList самостоятельно.

Как я могу разместить визуалы и позволить им добавлять декларативно с использованием XAML?

1 Ответ

0 голосов
/ 01 февраля 2011

Хорошо, давным-давно, но вот решение, которое я нашел тогда ...

Коллекция: Обратите внимание на комментарии взлома.

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

И элемент управления, который вы можете использовать в 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;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...