XAMLで作る簡単メーターコントロール

いつも、センサー、センサー、云うてますやん。データ計測したら見たいですやん。…という事で、XAMLで作るメーターコントロールを紹介します。

見た目は、こんな感じ。タイトルは変更可能、数字をセットすると針が動くというものです。

XAMLはざっと

     <Canvas>        <TextBlock Name="tbTitle" Text="Electric Power" FontSize="20"  HorizontalAlignment="Center" Height="32" Width="200" Canvas.Left="20" Canvas.Top="0" />        <TextBlock Name="tbValue" Text="1000000" FontSize="20" Canvas.Top="38" Canvas.Left="75"/>        <TextBlock Name="tbUnit" Text="Watt" FontSize="20" Canvas.Top="128" Canvas.Left="96"/><!-- 5つのRectangleは、目盛 -->        <Rectangle Width="20" Height="4" >            <Rectangle.Fill>                <SolidColorBrush Color="Red"/>            </Rectangle.Fill>            <Rectangle.RenderTransform>                <TranslateTransform X="10" Y="178"/>            </Rectangle.RenderTransform>        </Rectangle>        <Rectangle Width="20" Height="4" >            <Rectangle.Fill>                <SolidColorBrush Color="Red"/>            </Rectangle.Fill>            <Rectangle.RenderTransform>                <TransformGroup>                    <TranslateTransform X="10" Y="178"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="45"/>                </TransformGroup>            </Rectangle.RenderTransform>        </Rectangle>        <Rectangle Width="20" Height="4" >            <Rectangle.Fill>                <SolidColorBrush Color="Red"/>            </Rectangle.Fill>            <Rectangle.RenderTransform>                <TransformGroup>                    <TranslateTransform X="10" Y="178"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="90"/>                </TransformGroup>            </Rectangle.RenderTransform>        </Rectangle>        <Rectangle Width="20" Height="4" >            <Rectangle.Fill>                <SolidColorBrush Color="Red"/>            </Rectangle.Fill>            <Rectangle.RenderTransform>                <TransformGroup>                    <TranslateTransform X="10" Y="178"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="135"/>                </TransformGroup>            </Rectangle.RenderTransform>        </Rectangle>        <Rectangle Width="20" Height="4" >            <Rectangle.Fill>                <SolidColorBrush Color="Red"/>            </Rectangle.Fill>            <Rectangle.RenderTransform>                <TransformGroup>                    <TranslateTransform X="10" Y="178"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="180"/>                </TransformGroup>            </Rectangle.RenderTransform>        </Rectangle><!-- 目盛のアーチ -->        <Path Stroke="Black" StrokeThickness="1" Canvas.Top="80" Canvas.Left="20">            <Path.Data>                <PathGeometry>                    <PathGeometry.Figures>                        <PathFigure StartPoint="0,100">                            <PathFigure.Segments>                                <ArcSegment                                    Size="100,100" RotationAngle="-45"                                    IsLargeArc="True" SweepDirection="Clockwise"                                    Point="200,100"/>                            </PathFigure.Segments>                        </PathFigure>                    </PathGeometry.Figures>                </PathGeometry>            </Path.Data>        </Path><!-- 目盛の数字だよ -->        <TextBlock Text="0" FontSize="14">            <TextBlock.RenderTransform>                <TranslateTransform X="30" Y="170"/>            </TextBlock.RenderTransform>        </TextBlock>        <TextBlock Text="10" FontSize="14">            <TextBlock.RenderTransform>                <TransformGroup>                <TranslateTransform X="30" Y="170"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="45"/>                </TransformGroup>            </TextBlock.RenderTransform>        </TextBlock>        <TextBlock Text="100" FontSize="14">            <TextBlock.RenderTransform>                <TransformGroup>                <TranslateTransform X="30" Y="170"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="90"/>                </TransformGroup>            </TextBlock.RenderTransform>        </TextBlock>        <TextBlock Text="1000" FontSize="14">            <TextBlock.RenderTransform>                <TransformGroup>                <TranslateTransform X="30" Y="170"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="135"/>                </TransformGroup>            </TextBlock.RenderTransform>        </TextBlock>        <TextBlock Text="10000" FontSize="14">            <TextBlock.RenderTransform>                <TransformGroup>                <TranslateTransform X="30" Y="170"/>                    <RotateTransform CenterX="120" CenterY="180" Angle="180"/>                </TransformGroup>            </TextBlock.RenderTransform>        </TextBlock><!-- 針だよ -->        <Path Stroke="Orange" StrokeThickness="1" Canvas.Top="75" Canvas.Left="115" Opacity="70">            <Path.Data>                <PathGeometry>                    <PathGeometry.Figures>                        <PathFigure StartPoint="5,0">                            <PathFigure.Segments>                                <LineSegment Point="0,110"/>                                <LineSegment Point="10,110"/>                                <LineSegment Point="5,0"/>                            </PathFigure.Segments>                        </PathFigure>                    </PathGeometry.Figures>                    <PathGeometry.Transform>                        <RotateTransform x:Name="indicatorRotation" Angle="-90" CenterX="5" CenterY="105"/>                    </PathGeometry.Transform>                </PathGeometry>            </Path.Data>            <Path.Fill>                <SolidColorBrush Color="Orange"/>            </Path.Fill>        </Path>    </Canvas>

で、コードビハインドは、

     public partial class RoundMeterPart : UserControl    {        public RoundMeterPart()        {            InitializeComponent();        }         public string MeterTitle        {            get { return tbTitle.Text; }            set { tbTitle.Text = value; }        }         public string MeterUnit        {            get { return tbUnit.Text; }            set { tbUnit.Text = value; }        }         public double MeterValue        {            set            {                tbValue.Text = value.ToString();                                double angle = -90;                if (value > 1)                {                    double lvalue = System.Math.Log10(value);                    angle += lvalue * 45;                }                indicatorRotation.Angle = angle;            }        }    }
  
 こんな感じ。これで、Meterプロパティに値をぶっこめば、対数化された値で針の角度が変わります。
でもこれだと、値を更新した時に針が飛び飛びに動いて、それっぽくないですね。それっぽくするためにアニメーションを活用します。
 MeterValueプロパティのsetの実装を以下のように変えます。
         public double MeterValue        {            set            {                tbValue.Text = value.ToString();                                double angle = -90;                if (value > 1)                {                    double lvalue = System.Math.Log10(value);                    angle += lvalue * 45;                }                Duration duration = new Duration(TimeSpan.FromMilliseconds(500));                DoubleAnimation animation = new DoubleAnimation(angle, duration);                indicatorRotation.BeginAnimation(RotateTransform.AngleProperty, animation);            }        }
 こうすれば、古い値から新しい値の角度に滑らかに変わります。修正はたったの3行。ぱっと見、XAMLは煩雑だけど、あっという間に、らしい部品の出来上がりです。