我想构建一个带有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 );
}
同时定义并注册ReverseOrder
,如果更改,请致电UpdateLayout
。
答案 0 :(得分:12)
您可以重新实现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。
答案 1 :(得分:3)
MeasureOverride和ArrangeOverride
实际上,您的度量逻辑可能与StackPanel相同,因此您可能只能覆盖ArrangeOverride。请注意,StackPanel有一些处理滚动的逻辑,如果您自己编写,可能需要复制。您可能希望直接从Panel继承而不尝试支持滚动。
请参阅面板上的MSDN页面中的Custom Panel Elements或编写自定义面板的各种博客条目,例如WPF Tutorial - Creating A Custom Panel Control或Creating Custom Panels In WPF。
答案 2 :(得分:0)
这是另一种变体。它基于StackPanel
&#39; reference source,并且能够处理项目对齐。
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;
}
}