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