自定义C1Gauge控件的外观并实现其动态效果

发布时间:2013/06/01 00:06 发布者:jian

返回博客中心

在使用C1Gauge控件时积累一些很有用的经验,在这里可以和大家分享一下。主要是两个方面:
一、自定义C1Gauge控件的外观。
    默认的Gauge控件外观无法满足高用户体验的需求,因此需要自定义控件的外观。
(1)对仪器表盘外观的自定义
在XAML中,通过对Gauge控件的FaceTemplate属性进行编写,可以做到很多有价值的效果,如:修改仪器表盘的形状、使整体美观等。
在代码的实现上,可以参照ComponentOne的官方DEMO中的Speedometers,其中包含的FaceTemplate的用法值得借鉴。
在此贴出其中使用FaceTemplate的代码段给大家分享一下:

<c1:C1RadialGauge.FaceTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="0.03*" />
                        <RowDefinition Height="0.02*" />
                        <RowDefinition Height="0.848*" />
                        <RowDefinition Height="0.072*" />
                        <RowDefinition Height="0.03*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="0.032*" />
                        <ColumnDefinition Width="0.018*" />
                        <ColumnDefinition Width="0.867*" />
                        <ColumnDefinition Width="0.05*" />
                        <ColumnDefinition Width="0.033*" />
                    </Grid.ColumnDefinitions>
                    <Path Stretch="Uniform" Stroke="#FF8D8D8D" Data="M371.66751,0.5 C398.54837,98.324493 406.9313,186.78342 391.16183,284.59363 C405.31677,305.35202 415.47299,351.00616 386.32697,380.46704 C359.79633,407.28427 319.9631,403.50571 292.96335,390.98608 C195.27484,406.7576 98.225914,399.52081 0.52357554,371.66711 C0.50038487,371.35764 0.50000364,371.0484 0.5,370.73914 C0.50000364,166.55817 166.59108,0.97830737 371.66751,0.5 z" Grid.ColumnSpan="5" Grid.RowSpan="5">
                        <Path.Fill>
                            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                <GradientStop Color="#FFA0A0A0" />
                                <GradientStop Color="#FFFFFFFF" Offset="0.799" />
                                <GradientStop Color="#FFC4C4C4" Offset="1" />
                            </LinearGradientBrush>
                        </Path.Fill>
                    </Path>
                    <Path Stretch="Uniform" Stroke="#FF8D8D8D" Data="M371.66751,-0.88071233 C398.54837,96.943787 404.33206,192.68999 388.56259,290.50061 C400.33197,307.50589 414.90622,349.21121 388.24902,378.96298 C361.45685,408.86542 315.66614,395.47595 298.66266,388.61816 C200.97397,404.38968 95.764549,398.90549 -1.9378005,371.05179 C-1.9609913,370.74231 -2.261415,370.75574 -2.2614188,370.44647 C-1.091743,272.38522 39.302441,180.92236 105.74311,113.2928 C176.39317,41.378529 275.98953,-3.5868359 371.66751,-0.88071233 z" Grid.Column="1" Grid.Row="1" Grid.RowSpan="3" Grid.ColumnSpan="3">
                        <Path.Fill>
                            <RadialGradientBrush>
                                <RadialGradientBrush.RelativeTransform>
                                    <TransformGroup>
                                        <ScaleTransform CenterX="0.5" CenterY="0.5" ScaleY="1.439" ScaleX="1.469" />
                                        <SkewTransform CenterX="0.5" CenterY="0.5" />
                                        <RotateTransform CenterX="0.5" CenterY="0.5" />
                                        <TranslateTransform Y="0.327" X="0.338" />
                                    </TransformGroup>
                                </RadialGradientBrush.RelativeTransform>
                                <GradientStop Color="#FF2E3B51" Offset="0.009" />
                                <GradientStop Color="#FF040E1F" Offset="1" />
                            </RadialGradientBrush>
                        </Path.Fill>
                    </Path>
                    <Path Data="M339.83496,400.3598 C338.22495,384.3598 350.2038,296.3598 414.20099,232.35982 C463.99948,176 538.63409,153.43927 587.95782,153.43927 C593.4881,177.30829 597.28088,195.27232 598.47644,208 C598.47644,208 487.99896,191.99997 416.00192,264 C347.8858,332.11899 339.83496,400.3598 339.83496,400.3598 z" Fill="#19FFFFFF" Stretch="Uniform" Grid.Column="2" Grid.Row="2" />
                </Grid>
            </DataTemplate>
        </c1:C1RadialGauge.FaceTemplate>

参照上述例子,我们可以画出很多有创意的仪器来哦~~
(2)自定义指针形状
这个问题的解决方法在纠结了好几天之后终于搞定了。方法是:在静态资源中建立一个Style用于编辑指针形状,再在定义的Gauge标签中的PointerStyle属性赋值为资源中的那个Style即可。
分享个实例:
先在静态资源中编辑如下代码

            <Style x:Key="Pointer" TargetType="{x:Type c1:C1GaugePointer}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type c1:C1GaugePointer}">
                        <Path  x:Name="Root" Stretch="Fill" Fill="Red" Stroke="Red" Data="M278.25,-26.5 L277.75,80 271.5,159.5 271.5,239.5 C271.5,279.5 271.5,311.5 271.5,359.5 271.5,423.5 270.66667,412.83333 268,439.5 L294.5,439.5 C291.83333,412.83333 290,423.5 290,359.5 290,319.5 287.5,279.5 288.5,239.5 L287.5,159.5 280.75,80 280.25,-26.5 z" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

 

再在定义的Gauge控件中如下赋值:

<c1:C1RadialGauge  HorizontalAlignment="Left" x:Name="c1RadialGauge1" VerticalAlignment="Top"  PointerStyle="{StaticResource ResourceKey=Pointer}"  PointerWidth="0.03" PointerLength="0.6" PointerOffset="-.2" >

这样我们就能加入自己绘制的仪表指针~~

对线性仪表的动画效果可以通过参考官方DEMO就能做出来。而对于RadialGauge,我还没找到过其随用户数据变化而产生动画效果的例子。在此分享一下我的经验供大家交流。
我要实现的目标是:用一个Timer每一秒产生一个随机数,而仪表能够随着数据移动指针,并实现指针移动时的动画。
解决思路是:自定义一个类,用于存储两个数据:指针偏转前的数据值和需要偏转到的目标数据值。在每次产生新数据时触发的函数中启动动画效果函数,实现指针的移动。
以下是我的整个实现代码,希望高手批评指正。
XAML代码:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:c1="http://schemas.componentone.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="Gauge5.MainWindow"
        Title="MainWindow" Height="700" Width="600" Background="Black">
    <Window.Resources>
        <Storyboard x:Key="story1" Storyboard.TargetName="c1RadialGauge1" Storyboard.TargetProperty="(c1:C1RadialGauge.Value)"/>
            <Style x:Key="Pointer" TargetType="{x:Type c1:C1GaugePointer}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type c1:C1GaugePointer}">
                        <Path  x:Name="Root" Stretch="Fill" Fill="Red" Stroke="Red" Data="M278.25,-26.5 L277.75,80 271.5,159.5 271.5,239.5 C271.5,279.5 271.5,311.5 271.5,359.5 271.5,423.5 270.66667,412.83333 268,439.5 L294.5,439.5 C291.83333,412.83333 290,423.5 290,359.5 290,319.5 287.5,279.5 288.5,239.5 L287.5,159.5 280.75,80 280.25,-26.5 z" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <DataTemplate x:Key="MarkSmall">
            <Rectangle Height="4" Width="0.8" VerticalAlignment="Bottom" 
                    Fill="Wheat" Stretch="Fill" StrokeThickness="1" >
            </Rectangle>
        </DataTemplate>
        <DataTemplate x:Key="MarkBig">
            <Rectangle Height="8" Width="0.5" VerticalAlignment="Bottom" 
                    Fill="Wheat" Stretch="Fill" StrokeThickness="0" />
        </DataTemplate>
    </Window.Resources>
    <Grid  Background="Black" Margin="30">
            <c1:C1RadialGauge  HorizontalAlignment="Left" x:Name="c1RadialGauge1" VerticalAlignment="Top"
                           StartAngle="-135" SweepAngle="270" Minimum="0" Maximum="200" PointerStyle="{StaticResource ResourceKey=Pointer}"
                           PointerWidth="0.03" PointerLength="0.6" PointerOffset="-.2" Grid.RowSpan="3" Grid.ColumnSpan="2" PointerCapStroke="Red"
                           Background="Transparent" BorderBrush="White" BorderThickness="20" >
                <c1:C1RadialGauge.PointerCapFill>
                    <RadialGradientBrush>
                        <GradientStop Color="#FF232F43" Offset="0"/>
                        <GradientStop Color="#FFEF0A0A" Offset="1"/>
                        <GradientStop Color="#FFFA0000" Offset="0.737"/>
                        <GradientStop Color="#FF091425" Offset="0.703"/>
                    </RadialGradientBrush>
                </c1:C1RadialGauge.PointerCapFill>
                <c1:C1RadialGauge.FaceTemplate>
                    <DataTemplate>
                        <Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="0.04*"/>
                                <ColumnDefinition Width="0.92*"/>
                                <ColumnDefinition Width="0.04*"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="0.04*"/>
                                <RowDefinition Height="0.92*"/>
                                <RowDefinition Height="0.04*"/>
                            </Grid.RowDefinitions>
                            <Path   Grid.ColumnSpan="3" Grid.RowSpan="3" Stretch="Uniform" Data="F1 M 240.5,0.5C 373.048,0.5 480.5,107.952 480.5,240.5C 480.5,373.048 373.048,480.5 240.5,480.5C 107.952,480.5 0.5,373.048 0.5,240.5C 0.5,107.952 107.952,0.5 240.5,0.5 Z">
                                <Path.Fill>
                                    <RadialGradientBrush>
                                        <GradientStop Color="#FF0E161F" Offset="0"/>
                                        <GradientStop Color="#FF0E161F" Offset="0.267"/>
                                    <GradientStop Color="#FF2286FA" Offset="0.27"/>
                                        <GradientStop Color="#FF0E161F" Offset="0.353"/>
                                        <GradientStop Color="#FF0E161F" Offset="1"/>
                                    </RadialGradientBrush>
                                </Path.Fill>
                            </Path>
                            <Path Grid.ColumnSpan="3" Grid.RowSpan="3" Stretch="Uniform" Fill="White" Data="M 250.5,0.5C 388.571,0.5 500.5,112.429 500.5,250.5C 500.5,388.571 388.571,500.5 250.5,500.5C 112.429,500.5 0.500015,388.571 0.500015,250.5C 0.500015,112.429 112.429,0.5 250.5,0.5 Z M 250.5,5.49994C 385.81,5.49994 495.5,115.19 495.5,250.5C 495.5,385.81 385.81,495.5 250.5,495.5C 115.19,495.5 5.50002,385.81 5.50002,250.5C 5.50002,115.19 115.19,5.49994 250.5,5.49994 Z" StrokeThickness="0" >
                                <Path.Effect>
                                    <BlurEffect/>
                                </Path.Effect>
                            </Path>
                        </Grid>
                    </DataTemplate>
                </c1:C1RadialGauge.FaceTemplate>
                <c1:C1GaugeLabel From="0" To="200" Interval="20" Location="0.95" FontSize="18" FontWeight="UltraBlack" Foreground="Wheat"/>
                <c1:C1GaugeMark From="0" To="200" Interval="10" Location="1.05" Template="{StaticResource MarkBig}" />
                <c1:C1GaugeMark From="0" To="200" Interval="2.5" Location="1.075" Template="{StaticResource MarkSmall}"/>
            </c1:C1RadialGauge>
        </Grid>    
</Window>

C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.ComponentModel;
using System.Windows.Media.Animation;
namespace Gauge5
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        DispatcherTimer dt;
        Random rnd = new Random();
        public Data data1 = new Data();
        double range;
        public MainWindow()
        {
            InitializeComponent();
            //添加一个定时器,每秒产生一个数据
            range = c1RadialGauge1.SweepAngle;
            dt = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) };
            dt.Tick += (s, e) => getData();
            dt.Start();
        }
        public void getData()
        {   //产生的数据存入Data类的data1实例中
            double r = range * rnd.NextDouble();
            data1.DATA_former = data1.DATA_later;
            data1.DATA_later = r;
            Storyboard st = (Storyboard)this.FindResource("story1");
            DoubleAnimation da = new DoubleAnimation() { From = data1.DATA_former, To = data1.DATA_later, Duration = new TimeSpan(0,0,0,0,500) };
            st.Children.Add(da);
            this.BeginStoryboard(st);
        }
    }
    public class Data
    {
        public double DATA_former { get; set; }
        public double DATA_later { get; set; }
    }
}

 

原文地址:http://gcdn.grapecity.com/showtopic-8748.html


关于葡萄城

赋能开发者!葡萄城是专业的集开发工具、商业智能解决方案、低代码开发平台于一身的软件和服务提供商,为超过 75% 的全球财富 500 强企业提供服务。葡萄城专注控件软件领域30年,希望通过模块化的开发控件、灵活的低代码应用开发平台等一系列开发工具、解决方案和服务,帮助开发者快速响应复杂多变的业务需求,最大程度地发挥开发者的才智和潜能,让开发者的 IT 人生更从容更美好。

了解详情,请访问葡萄城官网