C# 在WPF中构建可逆堆叠面板

C# 在WPF中构建可逆堆叠面板,c#,.net,wpf,stackpanel,C#,.net,Wpf,Stackpanel,我想构建一个自定义的StackPanel,带有ReverseOrder属性,我可以声明性地将该属性设置为true,使StackPanel中的元素以与正常相反的顺序出现(例如从下到上或从右到左)。它需要在运行中可逆 我正在考虑从StackPanel派生一个新类,但我需要知道要重写哪些方法 最终解决方案: protected override System.Windows.Size ArrangeOverride( System.Windows.Size arrangeSize ) { do

我想构建一个自定义的
StackPanel
,带有
ReverseOrder
属性,我可以声明性地将该属性设置为true,使StackPanel中的元素以与正常相反的顺序出现(例如从下到上或从右到左)。它需要在运行中可逆

我正在考虑从StackPanel派生一个新类,但我需要知道要重写哪些方法

最终解决方案:

protected override System.Windows.Size ArrangeOverride( System.Windows.Size arrangeSize ) {
    double x = 0;
    double y = 0;

    IEnumerable<UIElement> children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse<UIElement>() : InternalChildren.Cast<UIElement>();
    foreach ( UIElement child in children ) {
        var size = child.DesiredSize;
        child.Arrange( new Rect( new Point( x, y ), size ) );

        if ( Orientation == Orientation.Horizontal )
            x += size.Width;
        else
            y += size.Height;
    }

    if ( Orientation == Orientation.Horizontal )
        return new Size( x, arrangeSize.Height );
    else
        return new Size( arrangeSize.Width, y );
}
受保护的覆盖System.Windows.Size ArrangeOverride(System.Windows.Size arrangeSize){
双x=0;
双y=0;
IEnumerable children=ReverseOrder?InternalChildren.Cast().Reverse():InternalChildren.Cast();
foreach(UIElement子元素中的子元素){
变量大小=child.DesiredSize;
排列(新矩形(新点(x,y),大小));
如果(方向==方向.水平)
x+=尺寸、宽度;
其他的
y+=尺寸、高度;
}
如果(方向==方向.水平)
返回新尺寸(x,arrangeSize.Height);
其他的
返回新大小(arrangeSize.Width,y);
}

还可以定义并注册
ReverseOrder
,并在更改时调用
UpdateLayout

您可以重新实现FrameworkElement.ArrangeOverride并调用所有子项。必要时,按与通常相反的顺序排列

类似于此(未经测试):

确保在更改ReverseOrder属性后调用UpdateLayout。

实际上,您的度量逻辑可能与StackPanel相同,因此您可以只覆盖ArrangeOverride。请注意,StackPanel具有一些处理滚动的逻辑,如果您自己编写滚动,则可能需要复制这些逻辑。您可能希望直接从面板继承,而不尝试支持滚动


请参阅MSDN页面中关于面板的内容,或关于编写自定义面板(如或)的各种博客条目

这是另一个变体。它基于
StackPanel
,并且能够处理项目对齐

public class ReversibleStackPanel : StackPanel
{
    public bool ReverseOrder
    {
        get => (bool)GetValue(ReverseOrderProperty);
        set => SetValue(ReverseOrderProperty, value);
    }

    public static readonly DependencyProperty ReverseOrderProperty =
        DependencyProperty.Register(nameof(ReverseOrder), typeof(bool), typeof(ReversibleStackPanel), new PropertyMetadata(false));


    protected override Size ArrangeOverride(Size arrangeSize)
    {
        bool fHorizontal = (Orientation == Orientation.Horizontal);
        var  rcChild = new Rect(arrangeSize);
        double previousChildSize = 0.0;

        var children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse() : InternalChildren.Cast<UIElement>();
        foreach (UIElement child in children)
        {
            if (child == null)
                continue;

            if (fHorizontal)
            {
                rcChild.X += previousChildSize;
                previousChildSize = child.DesiredSize.Width;
                rcChild.Width = previousChildSize;
                rcChild.Height = Math.Max(arrangeSize.Height, child.DesiredSize.Height);
            }
            else
            {
                rcChild.Y += previousChildSize;
                previousChildSize = child.DesiredSize.Height;
                rcChild.Height = previousChildSize;
                rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width);
            }

            child.Arrange(rcChild);
        }

        return arrangeSize;
    }
}
public类可逆堆栈面板:堆栈面板
{
公共布尔倒序器
{
get=>(bool)GetValue(ReverseOrderProperty);
set=>SetValue(ReverseOrderProperty,value);
}
公共静态只读依赖项Property ReverseOrderProperty=
DependencyProperty.Register(nameof(ReverseOrder)、typeof(bool)、typeof(ReversibleStackPanel)、new PropertyMetadata(false));
受保护的替代尺寸ArrangeOverride(尺寸arrangeSize)
{
水平方向=(方向==方向.水平);
var rcChild=new Rect(arrangeSize);
双倍以前的ChildSize=0.0;
var children=ReverseOrder?InternalChildren.Cast().Reverse():InternalChildren.Cast();
foreach(UIElement子元素中的子元素)
{
if(child==null)
继续;
if(水平)
{
rcChild.X+=以前的ChildSize;
previousChildSize=child.DesiredSize.Width;
rcChild.Width=以前的ChildSize;
rcChild.Height=Math.Max(arrangeSize.Height,child.DesiredSize.Height);
}
其他的
{
rcChild.Y+=以前的ChildSize;
previousChildSize=child.DesiredSize.Height;
rcChild.Height=以前的childsize;
rcChild.Width=Math.Max(arrangeSize.Width,child.DesiredSize.Width);
}
儿童。安排(rcChild);
}
返回安排大小;
}
}

完美!谢谢——我甚至不用想这个问题!;)反转uielements有什么影响?在ArrangeOverride中实际发生了什么?
public class ReversibleStackPanel : StackPanel
{
    public bool ReverseOrder
    {
        get => (bool)GetValue(ReverseOrderProperty);
        set => SetValue(ReverseOrderProperty, value);
    }

    public static readonly DependencyProperty ReverseOrderProperty =
        DependencyProperty.Register(nameof(ReverseOrder), typeof(bool), typeof(ReversibleStackPanel), new PropertyMetadata(false));


    protected override Size ArrangeOverride(Size arrangeSize)
    {
        bool fHorizontal = (Orientation == Orientation.Horizontal);
        var  rcChild = new Rect(arrangeSize);
        double previousChildSize = 0.0;

        var children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse() : InternalChildren.Cast<UIElement>();
        foreach (UIElement child in children)
        {
            if (child == null)
                continue;

            if (fHorizontal)
            {
                rcChild.X += previousChildSize;
                previousChildSize = child.DesiredSize.Width;
                rcChild.Width = previousChildSize;
                rcChild.Height = Math.Max(arrangeSize.Height, child.DesiredSize.Height);
            }
            else
            {
                rcChild.Y += previousChildSize;
                previousChildSize = child.DesiredSize.Height;
                rcChild.Height = previousChildSize;
                rcChild.Width = Math.Max(arrangeSize.Width, child.DesiredSize.Width);
            }

            child.Arrange(rcChild);
        }

        return arrangeSize;
    }
}