Silverlight 中的自定义面板:高级画布






2.14/5 (5投票s)
在这里,您将学习如何创建自己的自定义面板,类似于高级画布。
引言
有时,您想控制项目在屏幕上的显示位置,或许还想控制它们的大小。要做到这一点,您必须创建自己的面板版本,在其中您负责所有关于项目定位和尺寸调整的工作。
在本文中,您将学习如何创建自己的面板版本,包括使用额外的属性,如与常规Canvas
一起使用的Left
和Top
。我将指导您如何添加自己的属性并正确使用它们。
背景
我一直在寻找一个更高级的面板来满足我的需求。我想要完全控制我的项目在屏幕上的显示位置,比如在右下角。使用常规的Canvas
,这并不容易,除非您一直不断地收集面板的大小。此外,您必须在代码隐藏文件中进行此操作。我不想那样,所以我创建了自己的版本,它提供了这个功能,现在我与您分享,因为我认为常规的Canvas
应该这样扩展。
使用代码
该项目是用 Visual Studio 2008 和 .NET 3.5 框架创建的。如果您拥有较低的版本,仍然可以通过创建一个新的 Silverlight 应用程序并将 AdvancedCanvas.cs 和 Page.xaml 与 Page.xaml.cs 文件添加到您的项目中来运行它。
教程
现在,您将学习如何实际创建自己的 Panel
版本。首先,您必须创建一个扩展自 Panel
的新类。
public class AdvancedCanvas : Panel
为了让任何东西都能正常工作,您必须重写以下两个方法。对于所有从 Panel
派生的类,这是必需的!
protected override Size MeasureOverride(Size availableSize)
protected override Size ArrangeOverride(Size finalSize)
MeasureOverride
是一个方法,您将遍历所有子元素并确定是否需要更改它们的大小。ArrangeOverride
是一个方法,您将遍历所有子元素并计算它们的位置。
这是这两个方法的基本实现。如果您想查看完整的实现,请参阅附件项目。
protected override Size MeasureOverride(Size availableSize)
{
Size infinite = new Size(double.PositiveInfinity,
double.PositiveInfinity);
foreach (FrameworkElement child in Children)
{
child.Measure(infinite);
//Give the child all space it will need
}
return new Size(availableSize.Width, availableSize.Height);
}
protected override Size ArrangeOverride(Size finalSize)
{
//The location where the child will be displayed
double currentX = 0, currentY = 0;
foreach (FrameworkElement child in Children)
{
Point location = new Point(currentX, currentY);
child.Arrange(new Rect(location, child.DesiredSize));
//Calculate the new location
currentX += child.DesiredSize.Width;
currentY += child.DesiredSize.Height;
}
//Return the total size used
return new Size(currentX, currentY);
}
如果您想使用额外的属性,例如 Left 和 Right,您首先需要为每个属性添加三项内容:
- 一个附加的
DependencyProperties
,以属性名开头并以 property 结尾。 - 一个以 Get 开头并以属性名结尾的静态方法。
- 一个以 Set 开头并以属性名结尾的静态方法。
再次,简要展示如何将这些添加到您自己的面板中。
public static readonly DependencyProperty TopProperty =
DependencyProperty.RegisterAttached("Top", typeof(int),
typeof(AdvancedCanvas), null);
public static int GetTop(DependencyObject obj)
{ return (int)obj.GetValue(TopProperty); }
public static void SetTop(DependencyObject obj, int value)
{ obj.SetValue(TopProperty, value); }
使用附加的 DependencyProperty
,字符串 "Top" 用于将其注册为 Top,以便在设计器中使用。typeof(int)
定义了此属性的类型。您可以在其中放置一个枚举来限制用户可用的选项。typeof(AdvancedCanvas)
也必须在那里,因为它必须添加到此类中。如果您的类名不同,请在此处使用。通常使用 null
来通知属性何时已更改。在这种情况下,它不需要,因此为 null
。如果您想在此处添加一个回调,请使用以下代码并添加您在回调中指定的 方法名。
new PropertyMetadata(new PropertyChangedCallback(AdvancedCanvas.OnTopPropertyChanged)
在 GetTop
和 SetTop
方法中,您只需调用 DependencyObject
的 GetValue
和 SetValue
方法。您可以在其中添加额外的功能来执行一些验证,但越少越好。
现在您需要知道的就是如何在您的面板中使用这些属性。这非常简单。请记住,属性是设置在子元素上的,而不是面板本身。因此,在 MeasureOverride
和/或 ArrangeOverride
方法中使用子元素本身来获取其属性。
int top = (int)child.GetValue(TopProperty);
有了这个值,您就可以在代码中执行不同的测量或排列。
要在 .xaml 文件中使用您自己的面板,您首先需要加载它,即使它在同一个项目和目录中。您可以通过添加以下行并将其标记为本地命名空间来做到这一点。
xmlns:local="clr-namespace:Silverlight1"
Visual Studio 会帮助您处理这一行,所以您不必担心。
然后,您将您的面板添加到页面,现在您可以开始向其中添加项目,例如按钮。
<local:AdvancedCanvas HorizontalAlignment="Left"
VerticalAlignment="Top" Width="auto" Height="auto">
<Button local:AdvancedCanvas.Top="0"
local:AdvancedCanvas.Left="0" Content="TopLeft" />
<Button local:AdvancedCanvas.Top="0"
local:AdvancedCanvas.Center="0" Content="TopCenter" />
<Button local:AdvancedCanvas.Top="0"
local:AdvancedCanvas.Right="0" Content="TopRight" />
<Button local:AdvancedCanvas.Middle="0"
local:AdvancedCanvas.Left="0" Content="MiddleLeft" />
<Button local:AdvancedCanvas.Middle="0"
local:AdvancedCanvas.Center="0" Content="MiddleCenter" />
<Button local:AdvancedCanvas.Middle="0"
local:AdvancedCanvas.Right="0" Content="MiddleRight" />
<Button local:AdvancedCanvas.Bottom="0"
local:AdvancedCanvas.Left="0" Content="BottomLeft" />
<Button local:AdvancedCanvas.Bottom="0"
local:AdvancedCanvas.Center="0" Content="BottomCenter" />
<Button local:AdvancedCanvas.Bottom="0"
local:AdvancedCanvas.Right="0" Content="BottomRight" />
</local:AdvancedCanvas>
在这里,您看到使用了多个属性,这是合法的。您定义的所有属性都可以同时使用。
现在您已经了解了所有基础知识。对于更复杂的实现,您需要在 MeasureOverride
和 ArrangeOverride
中进行更多逻辑。请参阅附件项目,其中包含一个相当简单的实现。
技巧和窍门
通常,您希望您的面板具有完整的大小,除非另有定义。将其 Width
和 Height
标记为 Auto
,这样就可以了。如果您不这样做,它可能会获得不同的尺寸并对齐到可用空间的中心。如果这不是您想要的,请添加 HorizontalAlignment
和 VerticalAlignment
属性。
历史
- 2008-12-05:启动项目。
- 2008-12-06:完成项目并开始撰写文章。