在WPF中构建可逆的StackPanel

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

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

最终解决方案

 protected override System.Windows.Size ArrangeOverride( System.Windows.Size arrangeSize ) { double x = 0; double y = 0; IEnumerable children = ReverseOrder ? InternalChildren.Cast().Reverse() : InternalChildren.Cast(); 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 ); } 

还可以定义和注册ReverseOrder ,如果更改则调用UpdateLayout

您可以重新实现FrameworkElement.ArrangeOverride并在必要时以相反的顺序调用所有child.Arrange。

http://msdn.microsoft.com/en-us/library/system.windows.uielement.arrange.aspx

像这样的东西(未经测试):

  double x = 0; double y = 0; var children = ReverseOrder ? InternalChildren.Reverse() : InternalChildren; foreach (UIElement child in children) { var size = child.DesiredSize; child.Arrange(new Rect(new Point(x, y), size)); if (Orientation == Horizontal) x += size.Width; else y += size.Height; } 

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

MeasureOverride和ArrangeOverride

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

请参阅面板上的MSDN页面中的自定义面板元素或编写自定义面板的各种博客条目,例如WPF教程 – 创建自定义面板控件或在WPF中创建自定义面板 。

这是另一种变体。 它基于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().Reverse() : InternalChildren.Cast(); 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; } }