WPFユーザーコントロールの作成例(LedControl)
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");
サンプルの置き場所
作成したサンプルは次の場所に置いてあります。