ユーザーコン
トロールのDependencyPropertyが変更された時にイベントを発生させたい
昨日のIntegerUpDownコン
トロールの
Valueプロパティ、これが変更された時に何かの処理をしたくて、それにはイベントを追加するんだろうなとググって
デザイン画面で追加したユーザーコン
トロールの名前をupDownにしたところが
12行目
ユーザーコン
トロールを使う側のコードの方はこんな感じで29行目が
upDown.MyValueChanged += UpDown_MyValueChanged;
MyValueChangedが追加したイベント
upDownのMyValueChangedイベントを使って、イベント発生時にメッセージボックスを表示するようにしているのが
32行目からの
private void UpDown_MyValueChanged(object sender, IntegerUpDown.MyValueChangedEventArgs e)
{
string str = $"
Valueプロパティが変更されて{e.RoutedEvent.Name}イベント発生" + "\n";
MessageBox.Show(str + $"変更前の値は{e.MyOldValue}、新しい値は{e.MyNewValue}");
}
これを実行して
メッセージボックスが表示される、閉じると
変更された値に変化
ボタンのクリックイベントみたいに使いたかったわけね、クリックイベントが発生したら何かの処理をするみたいなの
今回はコピペでなんとかできたんだけど、このイベントを追加するってのがいつにも増してわからん
追加したイベントは名前をMyValueChangedにして
119行目から164行目までと355から386行目
イベントの効果は
DependencyPropertyの
Valueが変更された時に発生して、変更前後の値を渡してくれるっていうもの
前回は今の117行目が
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(
Value), typeof(int), typeof(IntegerUpDown));
こうだったのが今回は末尾に付け足して
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(
Value), typeof(int), typeof(IntegerUpDown)
,
new PropertyMetadata(new PropertyChangedCallback(MyValueChangedCallback)));
こう
ここまでの準備が長い…
まずは
MyValueChangedEventArgsクラス
(今回も自分で名前をつけるところには、目印になるよう頭にMyをつけた)
RoutedEventArgsクラスを継承したクラスが必要みたいなので作成
今見ていてこれはこうでもいいんじゃないかと
書き換えてみて動かしたら普通に動いた、こっちのが短くて良さそう
RoutedEventArgsってのはイベントのクラスなんだなあと
144行目のOnMyValueChanged
それでイベントを発生させているだけかな
デリゲートの宣言?
デリゲートは未だにわからん、Func<>に似ているらしい
MyValueChangedEventHandlerって名前にして、引数はobject型とさっき作ったクラスのMyValueChangedEventArgs
これが使われているのは2箇所
149行目のMyValueChangedがイベント自体?
この中でイベントをつけたり外したりしているみたい
ユーザーコン
トロールを使う側でコードを書く時に表示されるのはこれになる
155行目が…なんだろうこれRoutedEventあるからこれもイベントっぽいけど
けどこれでだいたい必要なのが揃って、これらを使うのが
159行目
DependencyProperty変更時に呼んで使うMyValueChangedCallback
引数からコントロール自体と変更前後の値を得られるみたいで
それを使ってさっき作ったクラスのMyValueChangedEventArgsをnewで作って
それを使ってOnMyValueChangedに渡してイベントを発生させている、のかな
最後に
DependencyPropertyの
Valueプロパティ
これの変更時にイベント発生させるのが目的だったのでここに
MyValueChangedCallbackを実行させるためにこうなった
119行目、最後の引数のPropertyMetadataの引数の
PropertyChangedCallbackの引数に
MyValueChangedCallbackを渡している
これで完成、ボタンコン
トロールのクリックイベントみたいに使えるようになった!
29行目でMyValueChangedイベント発生時に
32行目からのupDown_MyValueChanged(メッセージボックス表示)を実行
するように書いておいた場合
アプリを起動すると
29行目でupDownにイベントが登録されるので
149行目のMyValueChangedに行って151行目のaddで登録処理される
これでアプリ起動完了で
値を変更すると
159行目のMyValueChangedCallbackが呼ばれて
順番に処理されて
続いて
164行目でMyValueChangedEventArgsクラスを作成するので355行目
164行目に戻って
イベント発生したので
イベント発生時の処理が実行される、34行目
これでDependencyPropertyの変更時にイベント発生させるってのはできたけど
難しすぎる、理解できる気がしない
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Text.RegularExpressions;
using System.Windows.Controls.Primitives;
using System.Globalization;
namespace IntegerUpDown
{
<summary>
</summary>
public partial class IntegerUpDown : UserControl
{
public int Max
{
get { return (int)GetValue(MaxProperty); }
set { SetValue(MaxProperty, value); }
}
public static readonly DependencyProperty MaxProperty =
DependencyProperty.Register(nameof(Max), typeof(int), typeof(IntegerUpDown));
public int Min
{
get { return (int)GetValue(MinProperty); }
set { SetValue(MinProperty, value); }
}
public static readonly DependencyProperty MinProperty =
DependencyProperty.Register(nameof(Min), typeof(int), typeof(IntegerUpDown));
public int SmallChange
{
get { return (int)GetValue(SmallChangeProperty); }
set { SetValue(SmallChangeProperty, value); }
}
public static readonly DependencyProperty SmallChangeProperty =
DependencyProperty.Register(nameof(SmallChange), typeof(int), typeof(IntegerUpDown));
public int LargeChange
{
get { return (int)GetValue(LargeChangeProperty); }
set { SetValue(LargeChangeProperty, value); }
}
public static readonly DependencyProperty LargeChangeProperty =
DependencyProperty.Register(nameof(LargeChange), typeof(int), typeof(IntegerUpDown));
public double IntegerFontSize
{
get { return (double)GetValue(IntegerFontSizeProperty); }
set { SetValue(IntegerFontSizeProperty, value); }
}
public static readonly DependencyProperty IntegerFontSizeProperty =
DependencyProperty.Register(nameof(IntegerFontSize), typeof(double), typeof(IntegerUpDown));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(int), typeof(IntegerUpDown),
new PropertyMetadata(new PropertyChangedCallback(MyValueChangedCallback)));
public delegate void MyValueChangedEventHndler(object sender, MyValueChangedEventArgs e);
protected virtual void OnMyValueChanged(MyValueChangedEventArgs e)
{
RaiseEvent(e);
}
public event MyValueChangedEventHndler MyValueChanged
{
add { AddHandler(MyValueChangedEvent, value); }
remove { RemoveHandler(MyValueChangedEvent, value); }
}
public static readonly RoutedEvent MyValueChangedEvent =
EventManager.RegisterRoutedEvent(nameof(MyValueChanged),
RoutingStrategy.Bubble, typeof(MyValueChangedEventHndler), typeof(IntegerUpDown));
private static void MyValueChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var ctl = (IntegerUpDown)obj;
int newValue = (int)args.NewValue;
int oldValue = (int)args.OldValue;
ctl.OnMyValueChanged(new MyValueChangedEventArgs(MyValueChangedEvent, newValue, oldValue));
}
public IntegerUpDown()
{
InitializeComponent();
SmallChange = 1;
LargeChange = 1;
Width = 50;
Max = 10;
Min = 0;
Value = 0;
IntegerFontSize = 14f;
MyInitialize();
this.Loaded += IntegerUpDown_Loaded;
}
private void IntegerUpDown_Loaded(object sender, RoutedEventArgs e)
{
nTextBox.Width = Width - nScrollBar.Width;
}
private void MyInitialize()
{
nScrollBar.RenderTransform = new RotateTransform(180);
nScrollBar.RenderTransformOrigin = new Point(0.5, 0.5);
nTextBox.TextAlignment = TextAlignment.Right;
nTextBox.VerticalContentAlignment = VerticalAlignment.Center;
nStackPanel.Height = Height;
MySetBinding();
MySetEvents();
}
#region バインディング関連
private void MySetBinding()
{
var b = new Binding();
b.Source = this;
b.Path = new PropertyPath(IntegerUpDown.ValueProperty);
b.Converter = new ConverterInteger2Double();
nScrollBar.SetBinding(ScrollBar.ValueProperty, b);
b = new Binding();
b.Source = nScrollBar;
b.Path = new PropertyPath(ScrollBar.ValueProperty);
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
nTextBox.SetBinding(TextBox.TextProperty, b);
b = new Binding();
b.Source = this;
b.Path = new PropertyPath(MaxProperty);
b.Converter = new ConverterInteger2Double();
nScrollBar.SetBinding(ScrollBar.MaximumProperty, b);
b = new Binding();
b.Source = this;
b.Path = new PropertyPath(MinProperty);
b.Converter = new ConverterInteger2Double();
nScrollBar.SetBinding(ScrollBar.MinimumProperty, b);
b = new Binding();
b.Source = this;
b.Path = new PropertyPath(SmallChangeProperty);
b.Mode = BindingMode.OneWay;
nScrollBar.SetBinding(ScrollBar.SmallChangeProperty, b);
b = new Binding();
b.Source = this;
b.Path = new PropertyPath(LargeChangeProperty);
b.Mode = BindingMode.OneWay;
nScrollBar.SetBinding(ScrollBar.LargeChangeProperty, b);
b = new Binding();
b.Source = this;
b.Path = new PropertyPath(IntegerFontSizeProperty);
b.Mode = BindingMode.OneWay;
nTextBox.SetBinding(TextBox.FontSizeProperty, b);
}
#endregion
#region イベント関連
private void MySetEvents()
{
nTextBox.TextChanged += NTextBox_TextChanged;
nTextBox.LostFocus += NTextBox_LostFocus;
nTextBox.GotFocus += NTextBox_GotFocus;
nTextBox.MouseWheel += NTextBox_MouseWheel;
nScrollBar.MouseWheel += NScrollBar_MouseWheel;
}
private void NTextBox_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0) { nScrollBar.Value += SmallChange; }
else { nScrollBar.Value -= SmallChange; }
}
private void NScrollBar_MouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0) { nScrollBar.Value += LargeChange; }
else { nScrollBar.Value -= LargeChange; }
}
private void NTextBox_GotFocus(object sender, RoutedEventArgs e)
{
TextBox box = (TextBox)sender;
this.Dispatcher.InvokeAsync(() =>
{
Task.Delay(10);
box.SelectAll();
});
}
private void NTextBox_LostFocus(object sender, RoutedEventArgs e)
{
TextBox box = (TextBox)sender;
int i;
if (int.TryParse(box.Text, out i) == true)
{
Value = i;
}
else
{
Value = Min;
box.Text = Min.ToString();
}
}
private void NTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
TextBox box = (TextBox)sender;
double d;
if (!double.TryParse(box.Text, out d))
{
box.Text = Regex.Replace(box.Text, "[^0-9-]", "");
}
}
#endregion
}
internal class ConverterInteger2Double : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int i = (int)value;
return (double)i;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
double d = (double)value;
return (int)d;
}
}
public delegate void ValueChangedEventHandler(object sender, ValueChangedEventArgs e);
public class ValueChangedEventArgs : RoutedEventArgs
{
private int _value;
public ValueChangedEventArgs(RoutedEvent id, int num)
{
_value = num;
RoutedEvent = id;
}
public int Value { get { return _value; } }
}
public class MyValueChangedEventArgs : RoutedEventArgs
{
public MyValueChangedEventArgs(RoutedEvent id, int newValue, int oldValue)
{
MyNewValue = newValue;
MyOldValue = oldValue;
RoutedEvent = id;
}
public int MyNewValue { get; }
public int MyOldValue { get; }
}
}
太字のところが昨日から追加変更したところ
関連記事
2年後
2018/04/03は昨日