C# 如何装饰WPF面板?

C# 如何装饰WPF面板?,c#,.net,wpf,custom-controls,C#,.net,Wpf,Custom Controls,我想编写一个自定义面板,它将利用Decorator paten。这意味着它将有一些其他的面板作为属性。当某个元素添加到自定义面板时,我想将其也添加到装饰面板(存储在属性中),当某个元素被删除时,我也想将其从装饰面板中删除。我该怎么做 当发生对InternalChildrens的更改时,是否有一些方法要被重写或触发一些事件 多谢各位 编辑:基本上我想做一些像我想把任何面板动画之一。因此,我想用我的装饰器装饰任何面板,使其成为动画。我不完全理解此问题的上下文,但您可以覆盖OnVisualChildr

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

当发生对InternalChildrens的更改时,是否有一些方法要被重写或触发一些事件

多谢各位


编辑:基本上我想做一些像我想把任何面板动画之一。因此,我想用我的装饰器装饰任何面板,使其成为动画。

我不完全理解此问题的上下文,但您可以覆盖OnVisualChildrenChanged


不幸的是,你不能这么做

您将立即得到一个异常,表示控件只能有一个逻辑父级

虽然你能做的是双重授权。您的配电盘将测量/排列委托给另一个配电盘,作为回报,它将向其提供“重影”,这些重影将作为它的子对象,并将自己的测量/排列委托给您配电盘的子对象

代码如下:

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;
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Windows.Controls;
使用System.Windows;
公共类委派面板:面板
{
私有密封类DelegateChild:FrameworkElement
{
只读Func度量;
只读函数排列;
公共委托子对象(函数度量、函数排列)
{
这个.measure=度量;
安排;安排;
}
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸)
{
返回度量(可用性);
}
受保护的替代尺寸排列替代(尺寸最终化)
{
退货安排(最终化);
}
}
readonly Dictionary delegateByChild=新字典();
公共面板布局面板
{
获取{return(Panel)GetValue(LayoutPanelProperty);}
set{SetValue(LayoutPanelProperty,value);}
}
公共静态只读从属属性LayoutPanelProperty=
DependencyProperty.Register(“LayoutPanel”、typeof(Panel)、typeof(DelegatePanel)、new PropertyMetadata(null));
受保护的覆盖尺寸测量覆盖(尺寸可用尺寸)
{
if(this.LayoutPanel==null)
返回基准。测量超越(可用尺寸);
this.delegateByChild.Clear();
this.LayoutPanel.Children.Clear();
foreach(UIElement\u this.Children中的子元素)
{
var child=_child;
var delegateChild=新的delegateChild(
availableChildSize=>
{
child.Measure(可用childsize);
返回child.DesiredSize;
},
finalChildSize=>
{
返回finalChildSize;
});
delegateByChild[child]=delegateChild;
this.LayoutPanel.Children.Add(delegateChild);
}
this.LayoutPanel.Measure(availableSize);
返回this.LayoutPanel.DesiredSize;
}
受保护的替代尺寸排列替代(尺寸最终化)
{
if(this.LayoutPanel==null)
返回基数。安排覆盖(最终化);
this.LayoutPanel.Arrange(新Rect(最终化));
foreach(由子代指定的var kv)
{
var child=千伏钥匙;
var delegateChild=千伏值;
var position=delegateChild.TranslatePoint(默认值(点),this.LayoutPanel);
Rect finalChildBounds=新的Rect(
立场,,
delegateChild.RenderSize);
儿童。安排(最终儿童边界);
}
返回this.LayoutPanel.RenderSize;
}
}

免责声明:这不实现VirtualzingPanel。因此,虽然它在ItemsControl和gang内部工作,但对于大型集合来说,它的执行速度不够快。

我也这么想,但这是正确的做法吗?由于绑定而添加元素时是否也调用OnVisualChildrenChanged?这将是可取的。另一方面,当添加边框时,OnVisualChildren是否发生了变化?这是不可取的…什么样的动画,你希望能够与“任何面板”?不同类型的面板(网格、画布、stackpanel、dockpanel等)对于如何在其中定位项目具有完全不同的功能。我不认为有一个通用的方法来做你所描述的事情…有。但这是我的诀窍,很难描述。但是技术细节似乎对我来说是个问题:(当我第一次看“双重授权”时,我确信你说过,尽管你可以做的是玩。我完全同意。:)但是,请注意,DockPanel.Dock之类的东西不会从你的真实孩子传播到授权布局面板的鬼子。