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

Silverlight 3 和 WPF 的圆形仪表自定义控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (68投票s)

2009年7月22日

BSD

4分钟阅读

viewsIcon

435666

downloadIcon

22517

关于为 Silverlight 3 创建圆形仪表自定义控件的文章

circulargaugecontrol/gauge_cb.png

引言

Silverlight 3 SDK 和工具包包含一百多个控件,但缺少一个圆形仪表盘控件,所以我决定创建一个。我的目标是创建一个可自定义、易于使用且外观专业的仪表盘。您可以在 这里 看到实时演示。

Using the Code

在本节中,我将解释如何在您的应用程序中使用仪表盘控件。开始的最简单方法是在引用了 CircularGauge.dllCircularGauge 命名空间 之后,将此模板代码片段复制到您的项目中。

<!--Black Gauge -->
<gauge:CircularGaugeControl x:Name="myGauge1" 
  Grid.Column="0" Grid.Row="0" 
  Radius="150" 
  ScaleRadius="110" 
  ScaleStartAngle="120" 
  ScaleSweepAngle="300"
  PointerLength="85" 
  PointerCapRadius="35" 
  MinValue="0" 
  MaxValue="1000" 
  MajorDivisionsCount="10" 
  MinorDivisionsCount="5" 
  CurrentValue="{Binding Score}"
  ImageSource="silverlightlogo.png"
  ImageSize="60,50"
  RangeIndicatorThickness="8"
  RangeIndicatorRadius="120"
  RangeIndicatorLightRadius="10"
  RangeIndicatorLightOffset="80"
  ScaleLabelRadius="90"
  ScaleLabelSize="40,20"
  ScaleLabelFontSize="10"
  ScaleLabelForeground="LightGray"
  MajorTickSize="10,3"
  MinorTickSize="3,1"
  MajorTickColor="LightGray"
  MinorTickColor="LightGray"
  ImageOffset="-50"
  GaugeBackgroundColor="Black"
  PointerThickness ="16"
  OptimalRangeStartValue="300"
  OptimalRangeEndValue="700" 
  DialTextOffset="40" 
  DialText="Black"
  DialTextColor="Black"> 
</gauge:CircularGaugeControl>

CircularGauge 控件有多种选项可以完全自定义其所有元素。大多数属性设置都直观易用,因此我只在此讨论其中几个。

属性注释
背景设置背景颜色将自动创建渐变和玻璃效果,使用设定的颜色作为基础。这使得彻底改变外观变得非常容易。
ScaleRadiusScaleLabelRadiusRangeIndicatorRadius这些属性提供了将刻度、范围指示器和刻度标签放置在仪表盘内任何位置的选项。
CurrentValueCurrentValue 属性是一个依赖属性,因此您可以对其进行数据绑定。
ImageOffsetDialTextOffsetRangeIndicatorLightOffset这些属性控制着图像、刻度盘文本和范围指示器灯相对于仪表盘中心的 Y 轴位置。
OptimalRangeStartValueOptimalRangeEndValue这些属性有助于定义推荐的值范围。范围指示器是基于这些值绘制的。除了范围指示器外,RangeIndicatorLight 也提供使用相同信息的视觉反馈。代表这些值区域的颜色可以通过 BelowOptimalRangeColorAboveOptimalRangeColorOptimalRangeColor 值进行自定义。

创建自定义模板

这是一个无外观的控件,因此外观的所有细节都描述在 generic.xaml 中指定的默认样式中。如果您想创建新的控件模板,仪表盘控件在其控件模板中需要以下元素:

元素名称元素类型
LayoutRootGrid
指针Path
RangeIndicatorLight椭圆
PointerCap椭圆

您可以在源代码中包含的 generic.xaml 文件中找到默认样式的完整标记。

关注点

本节概述了创建此控件的主要步骤。仪表盘控件的视觉表示的大部分是通过 Expression Blend 绘制的。包含仪表盘所有元素的容器是一个 Grid。仪表盘/轮辋、指针盖、指针、范围指示器灯和玻璃效果(另一个不透明度较低的椭圆)都是通过 Expression Blend 3 绘制的。我绘制了形状,然后通过模板绑定了高度、宽度和其他属性。这是指针的标记:

 <!-- Pointer -->
<Path x:Name="Pointer" Stroke="#FFE91C1C" StrokeThickness="2" 
  Width="{TemplateBinding PointerLength}" 
  Height="{TemplateBinding PointerThickness}" HorizontalAlignment="Center"
  Data="M1,1 L1,10 L156,6 z" Stretch="Fill" RenderTransformOrigin="0,0.5" 
  RenderTransform="{Binding RelativeSource={RelativeSource TemplatedParent}, 
  Path=PointerLength, Converter={StaticResource pointerCenterConverter}}">
<Path.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF890A0A" Offset="0.197"/>
<GradientStop Color="#FFC40808" Offset="1"/>
<GradientStop Color="#FFE32323" Offset="0.61"/>
</LinearGradientBrush>
</Path.Fill>

</Path>

模板中您想在代码中访问的所有项目都需要适当地命名。这是建立用户界面和控件之间绑定的方法。然后我们重写 OnApplyTemplate 方法以访问 UI 中的命名元素。

绘制刻度和范围指示器

无法在 generic.xaml 文件中定义的元素是刻度和范围指示器,它们需要在代码中绘制。主刻度和次刻度只是矩形,通过渲染变换进行了旋转和移动。与刻度线类似,刻度标签是文本块,它们也被旋转和移动了。为了绘制刻度,我们需要计算刻度圆周上的点的位置。可以使用此公式计算:

circulargaugecontrol/gauge_formula4.png

给定角度和半径,在圆周上找到点的公式

x = a + r * cos(θ)
y = b + r * sin(θ)

其中

  • r 是圆的半径
  • (a,b) 是圆心
  • (x,y) 是圆周上的点
  • θ 是角度,以度为单位
  • 弧度 = 度数 * π/180

与绘制刻度类似,我们使用相同的公式来计算构成范围段的四个点。

circulargaugecontrol/gauge_formula3.png

动画指针

最后,动画指针仅涉及创建一个双精度动画,并将其目标设置为指针的旋转变换角度。

void AnimatePointer(double oldcurrentvalueAngle, double newcurrentvalueAngle)
{
    if (pointer != null)
    {
        DoubleAnimation da = new DoubleAnimation();
        da.From = oldcurrentvalueAngle;
        da.To = newcurrentvalueAngle;

        double animDuration = Math.Abs(oldcurrentvalueAngle - newcurrentvalueAngle) * 
                                       animatingSpeedFactor;
        da.Duration = new Duration(TimeSpan.FromMilliseconds(animDuration));

        Storyboard sb = new Storyboard();
        sb.Completed += new EventHandler(sb_Completed);
        sb.Children.Add(da);
        Storyboard.SetTarget(da, pointer);
        Storyboard.SetTargetProperty(da, new PropertyPath(
          "(Path.RenderTransform).(TransformGroup.Children)[0].(RotateTransform.Angle)"));

        if (newcurrentvalueAngle != oldcurrentvalueAngle)
        {
            sb.Begin();
        }
    }
}

WPF 版本

移植到 WPF 非常容易,我所要做的就是创建一个 WPF 自定义控件项目,然后将 Silverlight 版本中的代码移过来,一切都无需修改即可正常工作。

结论

此代码根据 Free BSD 许可证授权,因此可以免费用于商业应用程序。希望这个仪表盘有用,并非常感谢任何评论/反馈。

历史

  • 版本 1.0 - 2009 年 7 月 22 日
  • WPF 版本更新 - 2009 年 7 月 28 日
© . All rights reserved.