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

Silverlight 3 的可定制加载指示器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (15投票s)

2009年11月25日

CPOL

3分钟阅读

viewsIcon

75160

downloadIcon

2012

一篇关于为 Silverlight 3 创建可定制加载指示器的文章

Loading Indicators

引言

我一年前写了这篇文章的第一个版本。我的 Silverlight 应用程序需要一个简单的加载指示器,类似于旋转的轮子。我找到了一些控件,但是...有些太复杂了,有些很难定制。最后,我创建了自己的控件并在 CodeProject 上发表了一篇文章。收到的反馈迫使我回到代码并使其更好更简单。

这是第二次尝试。点击链接在我的网站上查看工作的 加载指示器演示

第二个版本中做了哪些更改

  • 为 Silverlight 4 重新打包
  • 删除了一些无用的属性
  • 简化了控件模板
  • 优化了动画

背景

关于我计划创建的内容的一些说明。首先,它应该是一个简单的、可定制的控件。唯一的限制 - 我不想硬编码它的几何形状,即动画元素的形状。此元素在 Generic.xaml 文件中定义,但可以作为用户 Style 的一部分重新定义。

如果您查看 Generic.xaml,您将只看到一个动画元素 AnimationElementTemplate 被定义为 DataTemplate。问题是如何复制它。我很惊讶地发现,在 Silverlight 中进行深度对象克隆是一项具有挑战性的任务。如果在 WPF 中需要三行代码(这是指向 示例 的链接),那么对于 Silverlight 来说,没有简单的解决方案。

起初,我从 Thilo Ruppert 的一篇精彩文章 Professional Drag and Drop Manager Control for Silverlight 2 中借用了一段克隆对象的代码。但后来,我遵循了 Nicolas Dorier's 使用 DataTemplate 作为动画元素的建议,并根据需要多次加载它。感谢 Nicolas 的评论。

所以,现在我们有了一个动画元素,并且我们知道如何制作它的副本。让我们看看它是如何工作的。

工作原理

下载我的演示解决方案并在 Visual Studio 中打开它。这是它的结构

LoadingIndicator Solution

SilverFlow.Controls 项目包含以下文件

LoadingIndicator.cs 定义控件的属性和行为
Generic.xaml 定义控件的默认模板

首先,让我们先看看 Generic.xaml

<Style TargetType="controls:LoadingIndicator">
    <Setter Property="Width" Value="42" />
    <Setter Property="Height" Value="42" />
    <Setter Property="Count" Value="12" />
    <Setter Property="Duration" Value="0:0:1" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="controls:LoadingIndicator">
                <Canvas x:Name="PART_AnimationElementContainer" 
                    Background="{TemplateBinding Background}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="AnimationElementTemplate">
        <Setter.Value>
            <DataTemplate>
                <Rectangle Fill="#00C0FF" Height="10" 
			Width="6" RadiusY="2" RadiusX="3" />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

它定义了控件的两个最重要的部分:PART_AnimationElementContainerAnimationElementTemplatePART_AnimationElementContainer 用作容器。动画元素将被复制 Count 次并放置到容器的内切圆中。它执行以下代码

for (int i = 0; i < this.Count; i++)
{
    // Copy base element
    FrameworkElement element = (FrameworkElement)AnimationElementTemplate.LoadContent();
    element.Opacity = 0;
 
    TranslateTransform tt = new TranslateTransform() { X = x, Y = y };
    RotateTransform rt = new RotateTransform() 
	{ Angle = i * angle + 180, CenterX = (width / 2), CenterY = -innerRadius };
    TransformGroup tg = new TransformGroup();
    tg.Children.Add(rt);
    tg.Children.Add(tt);
    element.RenderTransform = tg;
 
    animationElementContainer.Children.Add(element);
 
    DoubleAnimation animation = new DoubleAnimation()
    {
        From = animationElement.Opacity,
        To = EndOpacity,
        Duration = this.Duration,
        RepeatBehavior = RepeatBehavior.Forever,
        BeginTime = TimeSpan.FromMilliseconds
			((this.Duration.TotalMilliseconds / this.Count) * i)
    };
 
    Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity"));
    Storyboard.SetTarget(animation, element);
 
    Storyboard sb = new Storyboard();
    sb.Children.Add(animation);
    sb.Begin();
 
    storyboardList.Add(sb);
}

一个小技巧

感谢 Aaginor - 他指出了一个小问题。如果您将指示器的可见性更改为 Collapsed,动画仍然会运行,消耗资源。第一个想法是捕获类似 OnVisibilityChanged 的事件,但您很难找到这样的事件。好吧,有一个 LayoutUpdated 事件。并且它肯定会在控件更改其可见性时发生。但不仅在这种情况下。

这就是为什么我决定使用一个小技巧 - 创建一个 private ControlVisibility 属性并将它绑定到控件的 Visibility 属性

Binding binding = new Binding()
{
    Source = this,
    Path = new PropertyPath("Visibility")
};
 
this.SetBinding(LoadingIndicator.ControlVisibilityProperty, binding);

这使我可以在 OnControlVisibilityPropertyChanged 方法中拦截可见性的更改。当指示器变为不可见时,这里是停止动画的好地方。

当您运行演示时,您将看到一个“显示/隐藏指示器”按钮。它切换指示器的可见性。我添加它是为了检查我的代码是否真的可以处理不存在的 OnVisibilityChanged 事件。它可以!

Using the Code

加载指示器控件有两个 public 属性

Count 动画元素的数量。默认值为 12。
持续时间 一个动画循环持续时间。默认值为一秒。

查看 Styles.xaml,其中包含演示中显示的加载指示器的三个模板。第一个控件使用 Generic.xaml 中定义的内置样式。其他三个控件使用他们自己的样式。

历史

  • 2009 年 11 月 24 日:首次发布
  • 2009 年 12 月 8 日:添加了“一个小技巧”部分
  • 2010 年 11 月 28 日:简化了控件模板
© . All rights reserved.