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

为 Silverlight 2.0 开发自定义控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (21投票s)

2008 年 3 月 5 日

CPOL

5分钟阅读

viewsIcon

181906

downloadIcon

890

在本文中,我将介绍为 Silverlight 2.0 开发自定义控件的关键步骤

MediaButton Control

引言

本文的重点是向您展示构建 Silverlight 2.0 自定义控件并将其重用于您的 Silverlight 项目所需的步骤。

本文基于今天在 MIX08 上宣布的 Silverlight 2.0 Beta1。

在本文中,我们将创建一个控件库,并实现我们自己的 Button 类,该类除了具有不同的默认样式外,没有任何对默认实现的额外功能。通过重用此控件,您无需在应用程序或复合控件的所有 Button 实例中添加 Style 属性。

让我们开始吧。

创建项目

在 Visual Studio 2008 中创建一个 Silverlight 类库项目。

Creating the Project

由于这是一个控件库,我们需要添加对 System.Windows.Controls 程序集的引用。对于 Silverlight 2.0 Beta1,此程序集的版本号将为 1.0.0.0(别问为什么 :-)),并且默认情况下将来自“C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Libraries\Client\System.Windows.Controls.dll”。

在下一步中,我们将向我们的控件程序集添加 XmlnsDefinitionAttribute
此属性有助于 XAML 处理器查找 XML 命名空间和 CLR 命名空间并将它们配对。因此,请添加具有这些参数的属性:

[assembly: System.Windows.Markup.XmlnsDefinition 
 ("http://schemas.eyedea.hu/silverlight/2008/xaml/presentation", "Eyedea.Controls")]

创建控件类

在解决方案资源管理器中将 *Class1.cs* 重命名为 *MediaButton.cs*,并允许 Visual Studio 重构项目中的 Class1 类的名称引用。

接下来,我们将添加包含此控件库中控件默认样式的 XAML 文件。

让我们向项目添加一个文本文件类型的项,名为 *generic.xaml*。

Adding generic.xaml

在解决方案资源管理器中选择 *generic.xaml*,然后设置属性以将此文件以我们需要的格式嵌入:Resource
您需要删除“自定义工具”属性的值,并将“生成操作”设置为“Resource”。

Set generic.xaml properties

现在是时候编辑我们的主要目标:*MediaButton.cs*,所以打开它。

添加一个 using 语句来包含 System.Windows.Controls 命名空间,并让我们的 MediaButton 控件继承,因为它必须继承自内置的 Button 类。

此时,我们的 MediaButton 类将如下所示:

using System.Windows.Controls;

namespace Eyedea.Controls
{
    public class MediaButton : Button
    {
            public MediaButton()
            {
            }
    }
}

为控件添加默认样式

打开 *generic.xaml*。

首先,向 XAML 文件添加默认内容,并添加对我们的 XML 命名空间的引用。

<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Eyedea.Controls;assembly=Eyedea.Controls">
</ResourceDictionary>

请注意 local XML 命名空间前缀定义,它将在样式中使用来引用此控件库中的类型。

添加 Style 标签来定义我们样式的占位符。在 Style 标签的 TargetType 属性中,我们需要指定目标控件。在我们的例子中,它是我们的 MediaButton 控件。您还必须为 ControlTemplate 属性分配 TargetType

<Style TargetType="local:MediaButton">
    <Setter property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:MediaButton">
                <Grid x:Name="RootElement">
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Style 中,您可以定义控件的完整外观,包括用于视觉状态转换的 StoryBoard。视觉元素和 Storyboard 的名称非常重要,因为它们是 Silverlight 2.0 样式工作方式的基本组成部分,但由于现在超出了范围,将在另一篇文章中讨论。

当前按钮设计具有固定的宽度和高度,因此我们需要通过属性设置器来设置它们。
我们还指定了最小和最大尺寸以“保护”按钮的设计。

提示:简单的属性设置器应直接放在 Style 标签之后,Template 属性之前。

<!-- Common properties -->
<Setter property="IsEnabled" Value="true" />
<Setter property="IsTabStop" Value="true" />
<Setter property="Margin" Value="0" />
<Setter property="HorizontalContentAlignment" Value="Center" />
<Setter property="VerticalContentAlignment" Value="Center" />
<Setter property="Cursor" Value="Arrow" />
<Setter property="Foreground" Value="#CC808080" />
<!-- Text related properties -->
<Setter property="TextAlignment" Value="Left" />
<Setter property="TextWrapping" Value="NoWrap" />
<Setter property="FontSize" Value="11" />
<!-- Default Size Constraints -->
<Setter property="Width" Value="50" />
<Setter property="MinWidth" Value="50" />
<Setter property="MaxWidth" Value="50" />
<Setter property="Height" Value="22" />
<Setter property="MinHeight" Value="22" />
<Setter property="MaxHeight" Value="22" />

通过复制我们第一个 Expression Design 操作指南视频的结果样式 XAML 内容,将视觉元素添加到模板中。

设计包含一个背景矩形,一个轮廓矩形,以及两个将在用户交互期间动画的亮点。
底部有一个 ContentPresenter 元素,它是按钮 Content 属性的占位符。

将以下内容添加到 Grid 标签内:

<Grid.Resources>
    <Storyboard x:Key="MouseOver State">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="HighlightTop" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.3"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="HighlightBottom" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
    Storyboard.TargetName="Border"
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.7"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Key="Pressed State">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="HighlightTop" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="HighlightBottom" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.3"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="Border" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0.5"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Storyboard x:Key="Normal State" />
    <Storyboard x:Key="Disabled State">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="HighlightTop" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.1500000" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="HighlightBottom" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.1500000" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
    Storyboard.TargetName="ContentPresenter" 
    Storyboard.Targetproperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00.1500000" Value="0.7"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
</Grid.Resources>
<Rectangle Fill="#FF000000" Margin="2,2,2,2" RadiusX="1" RadiusY="1" Opacity="0.3"/>
<Rectangle x:Name="Border" Stroke="#FF808080" RadiusX="2" RadiusY="2" Opacity="0.3"/>
<Path x:Name="HighlightTop" Margin="2,2,2,11" Opacity="0.2" 
    Data="M0,1 C0,0.45 0.45,0 1,0 L45,0 C45.55,0 46,0.45 46,1 C46,1 46,9 46,9 
    C46,9 0,9 0,9 C0,9 0,1 0,1 z">
    <Path.Fill>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
            <GradientStop Color="#FFFFFFFF" Offset="0"/>
            <GradientStop Color="#FFE1E1E1" Offset="1"/>
        </LinearGradientBrush>
    </Path.Fill>
</Path>
<Path x:Name="HighlightBottom" Margin="2,11,2,2" Opacity="0" Data="M0,0 C0,0 31,0 
    46,0 C46,0 46,8 46,8 C46,8.55 45.55,9 45,9 L1,9 C0.45,9 0,8.55 0,8 C0,8 
    0,0 0,0 z">
    <Path.Fill>
        <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
            <GradientStop Color="#FFD6D6D6" Offset="0"/>
            <GradientStop Color="#FFFFFFFF" Offset="1"/>
        </LinearGradientBrush>
    </Path.Fill>
</Path>
<ContentPresenter x:Name="ContentPresenter"
    Content="{TemplateBinding Content}"
    ContentTemplate="{TemplateBinding ContentTemplate}"
    FontFamily="{TemplateBinding FontFamily}"
    FontSize="{TemplateBinding FontSize}"
    FontStretch="{TemplateBinding FontStretch}"
    FontStyle="{TemplateBinding FontStyle}"
    FontWeight="{TemplateBinding FontWeight}"
    Foreground="{TemplateBinding Foreground}"
    HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
    Padding="{TemplateBinding Padding}"
    TextAlignment="{TemplateBinding TextAlignment}"
    TextDecorations="{TemplateBinding TextDecorations}"
    TextWrapping="{TemplateBinding TextWrapping}"
    VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
/>

生成项目。如果一切顺利,此时您将拥有一个可正常工作的自定义控件库。

测试控件

要测试此控件,我们需要创建一个 Silverlight 应用程序项目。在解决方案资源管理器中,右键单击解决方案节点,然后向 Silverlight 应用程序类型的解决方案添加新项目。

Adding Test Project

对于 Silverlight 应用程序,Visual Studio 会询问我们希望为此 Silverlight 应用程序使用哪种测试方法。目前,一个测试 HTML 页面对我们来说已经足够了。

Test Project type

对于实际场景,例如混搭应用,需要 Web 应用程序,因为从文件系统运行的 Silverlight 应用程序或从 Web 服务器运行的应用程序访问外部资源的机制不同。

通过右键单击项目节点并选择“设置为启动项目”,将 TestApplication 项目标记为我们的启动项目。

将控件添加到测试项目中

要在我们的 TestApplication 中使用该控件,我们需要添加对控件库项目的引用。

Adding reference to Test Project

在设计器中打开 *Page.xaml* 并切换到 XAML 视图。要在页面中使用 MediaButton 控件,我们需要向 UserControl 标签添加 XML 命名空间定义。

测试页面将包含一个 4x3 的 Grid 和 2 个 MediaButton 实例,内容分别为“Play”和“Stop”。

用以下块覆盖 *Page.xaml* 的内容:

<UserControl x:Class="TestApplication.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:eyedea="clr-namespace:Eyedea.Controls;assembly=Eyedea.Controls"
    Width="320" Height="240">
        <Grid x:Name="LayoutRoot" Background="Black" Margin="50,50,50,50">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid.RenderTransform>
                <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="2" ScaleY="2" />
            </Grid.RenderTransform>
            <Rectangle Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1" 
        Stroke="#FF808080" RadiusX="2" RadiusY="2" Opacity="0.3"/>
            <eyedea:MediaButton Grid.Column="1" Grid.Row="1" Margin="2,2,2,2" 
        Content="Play">
            </eyedea:MediaButton>
            <eyedea:MediaButton Grid.Column="2" Grid.Row="1" Margin="2,2,2,2" 
        Content="Stop">
            </eyedea:MediaButton>
        </Grid>
</UserControl>

按 F5 并尝试该控件。对于 Silverlight 2.0,键盘支持比 Silverlight 1.0 好得多。现在您可以立即获得完整的 Tab 键支持。通过按几次 Tab 键进入浏览器中的 Silverlight 内容来尝试。

下一步

  • 我计划写一篇基于本文知识的文章,从头开始构建一个可皮肤的控件。
  • 以及更多关于 Silverlight 2.0 的内容 ;-)

关注点

历史

  • 2008 年 5 月 3 日 - 原始提交
  • 2008 年 5 月 6 日 - 添加了英语视频
  • 2008 年 3 月 23 日 - 更新了源代码存档 - 删除了 *ButtonBase.cs*
© . All rights reserved.