如何装饰WPF面板?

时间:2011-01-19 19:59:37

标签: c# .net wpf custom-controls

我想编写一个可以使用Decorator patern的自定义Panel。这意味着它将有一些其他Panel作为属性。当一些元素添加到我的自定义面板时,我想将它也添加到装饰面板(存储在属性中),当一些元素被删除时,我也想从装饰面板中删除它。我该怎么做?

当更改为InternalCholdrens时,是否有某些方法需要覆盖或触发某些事件?

谢谢

编辑:基本上我想做this之类的事我想把任何面板变成动画面板。所以我想用我的装饰器装饰任何面板,以便它变得动画。

2 个答案:

答案 0 :(得分:2)

不幸的是,你无法做到这一点。

您将立即获得的是一个例外,即控件只能有一个逻辑父级。

虽然你可以做的是做双重授权。您的小组代表会对另一个小组进行测量/安排,作为回报,它会为其提供“幽灵”作为孩子,并将自己的措施/安排委托给小组的孩子。

以下是代码:

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

免责声明:这不会实现VirtualizingPanel。因此,尽管它在ItemsControl和团队中工作,但它对于大型集合来说效率不高。

答案 1 :(得分:1)

我不完全理解这个问题的上下文,但你可以覆盖OnVisualChildrenChanged

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