为什么自定义面板不自动刷新?

本文关键字:刷新 自定义 为什么 | 更新日期: 2023-09-27 18:08:21

我已经编写了一个自定义面板。下面是代码:

public class GameBoardPanel:Panel
{
    public GameBoardPanel() { }
    public static readonly DependencyProperty SquareSideLengthProperty =
        DependencyProperty.Register("SquareSideLength", typeof(int), typeof(GameBoardPanel), new PropertyMetadata(0));
    public int SquareSideLength
    {
        get { return (int)GetValue(SquareSideLengthProperty); }
        private set { SetValue(SquareSideLengthProperty, value); }
    }
    public static readonly DependencyProperty RowsProperty =
        DependencyProperty.Register("Rows", typeof(int), typeof(GameBoardPanel), new PropertyMetadata(0));
    public int Rows
    {
        get { return (int)GetValue(RowsProperty); }
        set { SetValue(RowsProperty, value); }
    }
    public int Columns
    {
        get { return (int)GetValue(ColumnsProperty); }
        set { SetValue(ColumnsProperty, value); }
    }
    public static readonly DependencyProperty ColumnsProperty =
        DependencyProperty.Register("Columns", typeof(int), typeof(GameBoardPanel), new PropertyMetadata(0));
    public static readonly DependencyProperty RowProperty =
        DependencyProperty.RegisterAttached("Row", typeof(int), typeof(GameBoardPanel));
    public static readonly DependencyProperty ColumnProperty =
        DependencyProperty.RegisterAttached("Column", typeof(int), typeof(GameBoardPanel));
    public static void SetRow(DependencyObject control, int value)
    {
        control.SetValue(RowProperty, value);
    }
    public static int GetRow(DependencyObject control)
    {
        return (int)control.GetValue(RowProperty);
    }
    public static void SetColumn(DependencyObject control, int value)
    {
        control.SetValue(ColumnProperty, value);
    }
    public static int GetColumn(DependencyObject control)
    {
        return (int)control.GetValue(ColumnProperty);
    }
    protected override Size MeasureOverride(Size availableSize)
    {
        double min=Math.Min(availableSize.Width/Columns,availableSize.Height/Rows );
        SquareSideLength=(int)min;
        return new Size(SquareSideLength*Columns, SquareSideLength*Rows);
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        double min=Math.Min(finalSize.Width/Columns,finalSize.Height/Rows );
        SquareSideLength=(int)min;
        Size destinationSize = new Size(SquareSideLength * Columns, SquareSideLength * Rows);
        foreach (UIElement element in base.InternalChildren)
        {
            int row = GameBoardPanel.GetRow(element);
            int column = GameBoardPanel.GetColumn(element);
            element.Arrange(new Rect(column * SquareSideLength, row * SquareSideLength,SquareSideLength, SquareSideLength));
        }
        return destinationSize;
    }
}

这是一个非常简单的想法,类似于wpf Grid面板。我有一个控件,通过设置孩子GameBoardPanel.RowGameBoardPanel.Column附加属性来安排它的孩子在这样一个面板上。让我们假设我也有一个GameObject类,这是一个CustomControl,我把它添加到面板。比如说,我想把它移到左边。所以我这样做:

GameObject movable=new GameObject();
//setting properties such as GameBoardPanel.Row and GameBoardPanel.Column
panel.Children.Add(movable);
GameBoardPanel.SetColumn(GameBoardPanel.GetColumn(movable)-1);

让我们跳过movable对象可以移动到面板外的问题。这不是什么大问题。然而,如果我这样做,我没有看到任何效果。仅在添加额外行之后:

panel.InvalidateArrange(); 

我观察到物体向左移动。我很肯定,如果我对wpf Grid做同样的事情,就没有必要调用InvalidateArrange方法。所以,我很好奇为什么会发生这种情况?: D

为什么自定义面板不自动刷新?

您可以设置适当的属性元数据选项来告诉框架RowColumn附加属性会影响自定义面板的布局:

public static readonly DependencyProperty RowProperty =
    DependencyProperty.RegisterAttached("Row", typeof(int), typeof(GameBoardPanel),
        new FrameworkPropertyMetadata(0,
            FrameworkPropertyMetadataOptions.AffectsParentArrange));
public static readonly DependencyProperty ColumnProperty =
    DependencyProperty.RegisterAttached("Column", typeof(int), typeof(GameBoardPanel),
        new FrameworkPropertyMetadata(0,
            FrameworkPropertyMetadataOptions.AffectsParentArrange));

也就是说,您通常还应该在MeasureOverride方法中度量子元素:
protected override Size MeasureOverride(Size availableSize)
{
    double min = Math.Min(availableSize.Width / Columns, availableSize.Height / Rows);
    SquareSideLength = (int)min;
    foreach (UIElement element in InternalChildren)
    {
        element.Measure(new Size(SquareSideLength, SquareSideLength));
    }
    return new Size(SquareSideLength * Columns, SquareSideLength * Rows);
}

此外,SquareSideLength似乎也没有必要是一个依赖属性。它也可以是一个普通的CLR属性(或者可能只是一个私有字段)。它的类型最好是double而不是int

最后,你的MeasureOverride实现也应该为无限的availableSize参数值做好准备。从MSDN:

该文件的可用大小元素可以赋给子元素。无穷大可以用a表示值表示元素的大小将与内容的大小一致可用。