WPF用のユーザーコントロールです。 状態を表示する為のLEDのようなコントロールです。 表示色の設定とOn時の点滅機能も設けています。 [Visual Studio 2017、.NET4.5.2]

XAML
Blendでユーザーコントロールを作成します。 左側にLED形状の楕円と右側にテキストボックスを配置します。 楕円を配置するグリッドは、幅を自身の高さにバインドすることで正方形にします。それによって楕円は常に円となります。

楕円は3重にしてあります。最下層はLEDの色表示でLightという名前にします。(名前を付けることで、コードからアクセスできるようになります。)
2層目は点滅用に配置して、透過度で点滅を表現します。
最上層はLEDの周りのリングを表示するのと立体感をだすに使用しています。
<Grid Width="{Binding ActualHeight, ElementName=Light}">
<Ellipse x:Name="Light" StrokeThickness="0" Fill="#FFB0B0B0"/>
<Ellipse x:Name="FlickerCover" Fill="#00000000" Stroke="Black" StrokeThickness="0"/>
<Ellipse StrokeThickness="3">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.3,0.3" Center="0.3,0.3" RadiusX="0.4" RadiusY="0.4">
<GradientStop Offset="1"/>
<GradientStop Color="White"/>
</RadialGradientBrush>
</Ellipse.Fill>
<Ellipse.Stroke>
<RadialGradientBrush>
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="Black" Offset="1"/>
<GradientStop Color="#FFC7C7C7" Offset="0.748"/>
<GradientStop Color="White" Offset="0.923"/>
<GradientStop Color="#FF292929" Offset="0.679"/>
</RadialGradientBrush>
</Ellipse.Stroke>
</Ellipse>
</Grid>
アニメーション
FlickerStory と言う名前で、ストーリーボードを作成します。 その為には、Blend で、オブジェクトとタイムラインの (ストーリーボードは開いていません)の右にある+を押します。

Storyboard リソースの作成 ダイアログが開きます。

開いたダイアログで、Storyboard の名前を FlickerStory に変更してストーリーボードを作成します。
タイムラインの時刻を変えながら、プロパティーを変更してキーフレームを記録していくことで、ストーリーボードを作ります。

出来たストーリーボードは次のようなものになります。
<Storyboard x:Key="FlickerStory">
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="FlickerCover">
<EasingColorKeyFrame KeyTime="0" Value="Transparent">
<EasingColorKeyFrame.EasingFunction>
<CubicEase EasingMode="EaseInOut"/>
</EasingColorKeyFrame.EasingFunction>
</EasingColorKeyFrame>
<EasingColorKeyFrame KeyTime="0:0:0.5" Value="#7FFFFFFF"/>
<EasingColorKeyFrame KeyTime="0:0:1" Value="Transparent"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
Dependency Property
ユーザーコントロールとして使用する時のプロパティーを作成します。
これらはコードビハインドに配置します。
View に作成するプロパティーはDependency Propertyです。
FlickerOn: 点滅のOn/Off
FlickerRatio: 点滅のスピード
LedLightBrush: LightOnの時の色
LedOffBrush: LightOffの時の色
LightOn: Light On/Off
Title: Ledの右側の文字列
プロパティーが変更された時に呼ばれる ChangeFunc で表示の変更を行っています。
#region ******************************* LedLightBrush
[Category("LED")]
[Description("Led Light Brush")]
public Brush LedLightBrush
{
get { return (Brush)this.GetValue(LedLightColorProperty); }
set { this.SetValue(LedLightColorProperty, value); }
}
public static readonly DependencyProperty LedLightColorProperty =
DependencyProperty.Register("LedLightBrush", typeof(Brush),
typeof(LedControl),
new FrameworkPropertyMetadata(Brushes.Red,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
LedLightColorChangeFunc));
static void LedLightColorChangeFunc(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var of = (Brush)e.OldValue;
var nf = (Brush)e.NewValue;
var obj = (LedControl)target;
if (obj.LightOn) obj.Light.Fill = nf;
}
#endregion
#region ******************************* LedOffBrush
[Category("LED")]
[Description("Led off Brush")]
public Brush LedOffBrush
{
get { return (Brush)this.GetValue(LedOffBrushProperty); }
set { this.SetValue(LedOffBrushProperty, value); }
}
public static readonly DependencyProperty LedOffBrushProperty =
DependencyProperty.Register("LedOffBrush", typeof(Brush),
typeof(LedControl),
new FrameworkPropertyMetadata(Brushes.Gray,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
#endregion
#region ******************************* LightOn
[Category("LED")]
[Description("Led Light On")]
public bool LightOn
{
get { return (bool)this.GetValue(LightOnProperty); }
set { this.SetValue(LightOnProperty, value); }
}
public static readonly DependencyProperty LightOnProperty =
DependencyProperty.Register("LightOn", typeof(bool),
typeof(LedControl),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
LightOnChangeFunc));
static void LightOnChangeFunc(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var of = (bool)e.OldValue;
var nf = (bool)e.NewValue;
var obj = (LedControl)target;
if (nf)
{
obj.Light.Fill = obj.LedLightBrush;
if (obj.FlickerOn)
{
obj.board.RepeatBehavior = RepeatBehavior.Forever;
obj.board.Begin();
obj.board.SetSpeedRatio(obj.FlickerRatio);
}
}
else
{
obj.Light.Fill = obj.LedOffBrush;
obj.board.Stop();
}
}
#endregion
#region ******************************* Title
[Category("LED")]
[Description("Led Title")]
public string Title
{
get { return (string)this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string),
typeof(LedControl),
new FrameworkPropertyMetadata("LedControl",
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
TitleChangeFunc));
static void TitleChangeFunc(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var of = (string)e.OldValue;
var nf = (string)e.NewValue;
var obj = (LedControl)target;
obj.title.Text = nf;
}
#endregion
#region ******************************* FlickerOn
[Category("LED")]
[Description("Flicker On")]
public bool FlickerOn
{
get { return (bool)this.GetValue(FlickerOnProperty); }
set { this.SetValue(FlickerOnProperty, value); }
}
public static readonly DependencyProperty FlickerOnProperty =
DependencyProperty.Register("FlickerOn", typeof(bool),
typeof(LedControl),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
FlickerOnChangeFunc));
static void FlickerOnChangeFunc(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var of = (bool)e.OldValue;
var nf = (bool)e.NewValue;
var obj = (LedControl)target;
if(nf && obj.LightOn)
{
obj.board.RepeatBehavior = RepeatBehavior.Forever;
obj.board.Begin();
obj.board.SetSpeedRatio(obj.FlickerRatio);
}
if (!nf)
{
obj.board.Stop();
}
}
#endregion
#region ******************************* FlickerRatio
[Category("LED")]
[Description("Flicker Ratio")]
public double FlickerRatio
{
get { return (double)this.GetValue(FlickerRatioProperty); }
set { this.SetValue(FlickerRatioProperty, value); }
}
public static readonly DependencyProperty FlickerRatioProperty =
DependencyProperty.Register("FlickerRatio", typeof(double),
typeof(LedControl),
new FrameworkPropertyMetadata(1.0,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
FlickerRatioChangeFunc,
FlickerRatioCoerceFunc));
static void FlickerRatioChangeFunc(DependencyObject target,
DependencyPropertyChangedEventArgs e)
{
var of = (double)e.OldValue;
var nf = (double)e.NewValue;
var obj = (LedControl)target;
obj.board.SetSpeedRatio(nf);
}
static object FlickerRatioCoerceFunc(DependencyObject target, object baseValue)
{
var obj = (LedControl)target;
var val = (double)baseValue;
return val;
}
#endregion
このユーザーコントロールを貼り付けると、次のようなプロパティーが使用できるようになります。

点滅用のストーリーボードをコードビハインドから使用する為に、View のコンストラクターに、ストーリーボードを探すために次のようなコードを追加しておきます。
board = (Storyboard)FindResource("FlickerStory");
サンプルの置き場所
作成したサンプルは次の場所に置いてあります。
