为什么自定义面板不自动刷新
Why does the custom panel not refreshing automatically
我写了一个自定义面板。这是代码:
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.Row
和 GameBoardPanel.Column
附加属性将其子项安排在这样的面板上。假设我还有一个 GameObject
class,它是一个 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
您可以设置适当的 属性 元数据选项来告诉框架 Row
和 Column
附加属性会影响您的自定义面板的布局:
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:
The available size that this
element can give to child elements. Infinity can be specified as a
value to indicate that the element will size to whatever content is
available.
我写了一个自定义面板。这是代码:
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.Row
和 GameBoardPanel.Column
附加属性将其子项安排在这样的面板上。假设我还有一个 GameObject
class,它是一个 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
您可以设置适当的 属性 元数据选项来告诉框架 Row
和 Column
附加属性会影响您的自定义面板的布局:
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:
The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.