为啥自定义面板不自动刷新

Posted

技术标签:

【中文标题】为啥自定义面板不自动刷新【英文标题】:Why does the custom panel not refreshing automatically为什么自定义面板不自动刷新 【发布时间】:2015-08-17 10:32:37 【问题描述】:

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

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

【问题讨论】:

【参考方案1】:

您可以设置适当的属性元数据选项来告诉框架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:

这个可以使用的尺寸 element 可以赋予子元素。无穷大可以指定为 值来指示元素的大小将适应任何内容 可用。

【讨论】:

它工作正常。谢谢你。没有你的帮助,我不会得到它:P

以上是关于为啥自定义面板不自动刷新的主要内容,如果未能解决你的问题,请参考以下文章

探索SwipeRefreshLayout配合自定义ListView完成下拉刷新滑到底部自动加载更多

点击datagridview的列标题为啥不自动排序

iOS常用刷新控件(下拉、上拉)详解

CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在

Android 自定义可拖拽View,界面渲染刷新后不会自动回到起始位置

为啥我进入路由器网页后会一直自动刷新?