65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.14/5 (5投票s)

2008年12月6日

CPOL

4分钟阅读

viewsIcon

44174

downloadIcon

488

在这里,您将学习如何创建自己的自定义面板,类似于高级画布。

引言

有时,您想控制项目在屏幕上的显示位置,或许还想控制它们的大小。要做到这一点,您必须创建自己的面板版本,在其中您负责所有关于项目定位和尺寸调整的工作。

在本文中,您将学习如何创建自己的面板版本,包括使用额外的属性,如与常规Canvas一起使用的LeftTop。我将指导您如何添加自己的属性并正确使用它们。

背景

我一直在寻找一个更高级的面板来满足我的需求。我想要完全控制我的项目在屏幕上的显示位置,比如在右下角。使用常规的Canvas,这并不容易,除非您一直不断地收集面板的大小。此外,您必须在代码隐藏文件中进行此操作。我不想那样,所以我创建了自己的版本,它提供了这个功能,现在我与您分享,因为我认为常规的Canvas应该这样扩展。

使用代码

该项目是用 Visual Studio 2008 和 .NET 3.5 框架创建的。如果您拥有较低的版本,仍然可以通过创建一个新的 Silverlight 应用程序并将 AdvancedCanvas.csPage.xamlPage.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,您首先需要为每个属性添加三项内容:

  1. 一个附加的 DependencyProperties,以属性名开头并以 property 结尾。
  2. 一个以 Get 开头并以属性名结尾的静态方法。
  3. 一个以 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)

GetTopSetTop 方法中,您只需调用 DependencyObjectGetValueSetValue 方法。您可以在其中添加额外的功能来执行一些验证,但越少越好。

现在您需要知道的就是如何在您的面板中使用这些属性。这非常简单。请记住,属性是设置在子元素上的,而不是面板本身。因此,在 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>

在这里,您看到使用了多个属性,这是合法的。您定义的所有属性都可以同时使用。

现在您已经了解了所有基础知识。对于更复杂的实现,您需要在 MeasureOverrideArrangeOverride 中进行更多逻辑。请参阅附件项目,其中包含一个相当简单的实现。

技巧和窍门

通常,您希望您的面板具有完整的大小,除非另有定义。将其 WidthHeight 标记为 Auto,这样就可以了。如果您不这样做,它可能会获得不同的尺寸并对齐到可用空间的中心。如果这不是您想要的,请添加 HorizontalAlignmentVerticalAlignment 属性。

历史

  • 2008-12-05:启动项目。
  • 2008-12-06:完成项目并开始撰写文章。
© . All rights reserved.