开发者

How to decorate WPF Panel?

开发者 https://www.devze.com 2023-02-05 19:50 出处:网络
I want to write a custom Panel that would make use of Decorator patern. That means it will have some other Panel as a property. When some element is added to my custom panel I want to add it also to d

I want to write a custom Panel that would make use of Decorator patern. That means it will have some other Panel as a property. When some element is added to my custom panel I want to add it also to decorated panel (stored in property) and when some e开发者_StackOverflowlement is removed, I want to remove it from decorated panel as well. How do I do that ?

Is there some method that is to be overriden or some event is fired when change to InternalCholdrens happen ?

Thank you

EDIT: Basicly I want to do something like this I want to turn any panel to the animated one. So I want to decorate any panel with my decorator so it becomes animated.


You can't do that, unfortunately.

What you will get immediately is an exception saying a control can have only one logical parent.

Although what you can do is to do double-delegation. Your panel delegates measure/arrange to another panel, and in return it provides it with 'ghosts' which will act as a children to it and delegate their own measure/arrange to your panel's children.

Here's the code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;

public class DelegatePanel : Panel
{
    private sealed class DelegateChild : FrameworkElement
    {
        readonly Func<Size, Size> measure;
        readonly Func<Size, Size> arrange;

        public DelegateChild(Func<Size,Size> measure, Func<Size,Size> arrange)
        {
            this.measure = measure;
            this.arrange = arrange;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            return measure(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            return arrange(finalSize);
        }
    }

    readonly Dictionary<UIElement, UIElement> delegateByChild = new Dictionary<UIElement,UIElement>();

    public Panel LayoutPanel
    {
        get { return (Panel)GetValue(LayoutPanelProperty); }
        set { SetValue(LayoutPanelProperty, value); }
    }

    public static readonly DependencyProperty LayoutPanelProperty =
        DependencyProperty.Register("LayoutPanel", typeof(Panel), typeof(DelegatePanel), new PropertyMetadata(null));

    protected override Size MeasureOverride(Size availableSize)
    {
        if(this.LayoutPanel==null)
            return base.MeasureOverride(availableSize);

        this.delegateByChild.Clear();

        this.LayoutPanel.Children.Clear();
        foreach (UIElement _child in this.Children)
        {
            var child = _child;

            var delegateChild = new DelegateChild(
                    availableChildSize =>
                    {
                        child.Measure(availableChildSize);
                        return child.DesiredSize;
                    },
                    finalChildSize =>
                    {
                        return finalChildSize;
                    });

            delegateByChild[child] = delegateChild;

            this.LayoutPanel.Children.Add(delegateChild);
        }

        this.LayoutPanel.Measure(availableSize);
        return this.LayoutPanel.DesiredSize;
    }

    protected override Size  ArrangeOverride(Size finalSize)
    {
        if(this.LayoutPanel==null)
            return base.ArrangeOverride(finalSize);

        this.LayoutPanel.Arrange(new Rect(finalSize));

        foreach (var kv in delegateByChild)
        {
            var child = kv.Key;
            var delegateChild = kv.Value;

            var position = delegateChild.TranslatePoint(default(Point), this.LayoutPanel);

            Rect finalChildBounds = new Rect(
                position,
                delegateChild.RenderSize);

            child.Arrange(finalChildBounds);
        }

        return this.LayoutPanel.RenderSize;
    }
}

Disclaimer: this doesn't implement VirtualizingPanel. So whilst it does work inside ItemsControl and the gang -- it won't perform quick enough for large collections.


i don't totally understand the context for this question but you can override OnVisualChildrenChanged

http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.onvisualchildrenchanged.aspx

0

精彩评论

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

关注公众号