WPF Prism extra: 4 ~ Extended WPF Toolkit™ で数値と日付を入力 ~
このエントリの内容は元々 episode: 9 の一部でしたが、Prism には全く関係ない内容なので episode: 9、9′ の統合リニューアルに併せて extra シリーズとして分割・独立した記事としました。
このエントリでは Xceed 社が開発している Extended WPF Toolkit™ に含まれるコントロールの一部を紹介します。
尚、この記事は Visual Studio 2017 Community Edition で .NET Framework 4.7.2 以上 と C# + Prism 7.1 + ReactiveProperty を使用して 、WPF アプリケーションを MVVM パターンで作成するのが目的で、C# での基本的なコーディング知識を持っている人が対象です。
目次
WPF 標準の TextBox へ少数部のある数値を入力する
episode: 9 でも軽く紹介しましたが、WPF 標準の TextBox へ double 等、小数部のある数値を入力しようとしても通常の方法では入力できません。
詳しくは Qiita の『doubleとバインドしているTextBoxに小数点が入力できない!』 へ書かれていますが、『UpdateSourceTrigger = PropertyChanged』に設定された TextBox では小数点を入力しようとしても fig. 1 のように一度カーソルを戻さないと小数点が入力できません。
記事には続きがあって、以下の 2 エントリが解決編として公開されています。
最終的にコンバーターで対応しているようですが、管理人的には TextBox を継承した NumberText 等のカスタムコントロールを作成する方が良いかな…と思っています。
カスタムコントロールを自作する以外に Infragistics や GrapeCity 等の市販コンポーネントを購入する手もありますが、どちらも 10 万超えの高額製品なのでプライベート用途だけでは簡単に手が出せません。
市販コンポーネント以外に元々試してみようと思っていたフリーの WPF コンポーネント集があったのを思い出したので試してみました。
Extended WPF Toolkit™
フリーの WPF コンポーネント集である Extended WPF Toolkit™ は Xceed が開発・販売している製品の Community Edition で、元は CodePlex で配布していたようですが CodePlex 終了後、現在は GitHub + NuGet で 49 個のカスタムコントロールを含んだパッケージ(Ver.3.5.1 2019/7/21 現在)として配布されています。
数値入力コントロール以外にも MaskedTextBox、RichTextBox 等も含まれていて、現時点(2019年7月現在)でもバグフィックスは行われているようなので個人で作成するアプリに使用するなら十分だと思います。
但し対応は .NET Framework 4.0 までで .NET Framework 4.5 には未対応のようですし .NET Core 3.0 への対応も現時点(2019/7/21 現在)では不明なので業務用システム等への採用は難しいかもしれませんが、個人利用であればとりあえず使えそうな印象です。
Extended WPF Toolkit をインストールするには NuGet で『extended』と検索すると見つかります。
検索結果の【Extended.WPF.Toolkit】を使用するプロジェクト(ここでは EditorViews プロジェクト)へインストールして『PhysicalEditor.xaml』を src. 1 のように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <UserControl x:Class="WpfTestApp.Views.PhysicalEditor" ~ 略 ~ xmlns:xceed="http://schemas.xceed.com/wpf/xaml/toolkit" ~ 略 ~ prism:ViewModelLocator.AutoWireViewModel="True"> ~ 略 ~ <Grid> ~ 略 ~ <Grid Grid.Column="1" Grid.Row="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.25*"/> <ColumnDefinition Width="0.25*"/> <ColumnDefinition Width="0.25*"/> <ColumnDefinition Width="0.25*"/> </Grid.ColumnDefinitions> <xceed:DateTimePicker Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="10,0" Value="{Binding MeasurementDate.Value, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" Watermark="測定日を選択" AutoCloseCalendar="True" ShowButtonSpinner="False" TimePickerVisibility="Collapsed" Format="ShortDate" TextAlignment="Left" /> </Grid> ~ 略 ~ <Grid Grid.Column="1" Grid.Row="1" Margin="10,0,0,0"> ~ 略 ~ <Grid Grid.Column="0" Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.8*"/> <ColumnDefinition Width="0.2*"/> </Grid.ColumnDefinitions> <xceed:DoubleUpDown Grid.Column="0" Value="{Binding Height.Value, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" MaxLength="6" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" ShowButtonSpinner="False" Maximum="400" Minimum="0" ParsingNumberStyle="Float" /> <TextBlock Grid.Column="1" VerticalAlignment="Center" Text="cm" /> </Grid> <Grid Grid.Column="1" Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="0.8*"/> <ColumnDefinition Width="0.2*"/> </Grid.ColumnDefinitions> <xceed:DoubleUpDown Grid.Column="0" Value="{Binding Weight.Value, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" MaxLength="6" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" ShowButtonSpinner="False" Maximum="999" Minimum="0" ParsingNumberStyle="Float" /> <TextBlock Grid.Column="1" VerticalAlignment="Center" Text="kg" /> </Grid> ~ 略 ~ </Grid> </Grid> </Grid> </UserControl> |
まず、Extended WPF Toolkit を使用するために名前空間にエイリアスを追加します。(3 行目)
そして、WPF 標準の DatePicker を Extended WPF Toolkit の DateTimePickerに、TextBox を Extended WPF Toolkit の DoubleUpDown に置き換えています。
View に配置したコントロールを置き換える場合、XAML ならコントロール名を書き換えるだけでバインディングやマージン等の共通プロパティは修正する必要はありませんし、元のコントロールをコメントアウトして残しておくこともできます。
Windows Form ではコントロールをコメントアウトして残しておくようなことはできないので、このエントリのように別のコントロールを試してみたい場面等で簡単に元に戻すことができるのは画面レイアウトをテキストで記述する XAML ならではの利点と言えるでしょう。
(コメントアウトしたコントロールを元に戻すような用途は頻繁に無いかもしれませんが…)
Extended WPF Toolkit DoubleUpDown コントロール
以下の表はサンプルアプリに追加した Extended WPF Toolkit の DoubleUpDown コントロールに設定したプロパティの簡易説明一覧です。
Extended WPF Toolkit にはこの DoubleUpDown コントロールの他にも IntegerUpDown、DecimalUpDown、ByteUpDown 等数値の型ごとの NumericUpDown コントロールが含まれています。
プロパティ名 | 内容 |
---|---|
Value | WPF 標準の TextBox では Text プロパティですが、Value プロパティへ修正する必要があります。 |
AutoSelectBehavior | 【OnFocus】に設定していると、フォーカスを受け取った際にテキストが全選択されます。 |
MouseWheelActiveOnFocus | true に設定すると、マウスホイールで値の Up・Down ができるようになります。 |
MouseWheelActiveTrigger | 上記 MouseWheelActiveOnFocus = true に設定した場合、マウスホイールを受け取るトリガーを指定できます。 「フォーカスがある場合」、「マウスカーソルがコントロール上にある場合」等が選択できます。 |
ShowButtonSpinner | 入力エリアの UpDown ボタンの表示を取得・設定します。 |
Maximum | 入力可能な最大値を取得・設定します。 |
Minimum | 入力可能な最小値を取得・設定します。 |
ParsingNumberStyle | 入力可能な数値の形式を取得・設定します。 ここでは double 型の入力項目として使用するので『Float』を設定しています。 Float を設定してもアルファベット等は入力できますが、フォーカスが外れると無効な入力はクリアされます。 又、episode: 9 で紹介した Parse エラー等も発生しなくなります。 |
ここで紹介したプロパティはごく一部なので、上記以外のプロパティについては Extended WPF Toolkit の GitHub Wiki やオブジェクトブラウザ等で確認してください。
このサンプルアプリで使用している全数値入力コントロールを Extended WPF Toolkit のコントロールに入れ替えれば、前章で紹介した「小数点の入力にはカーソルを戻す必要がある」とか、「フォーカスを受け取ったらテキストを全選択しない」と言うような不満は解消できますが別の問題も発生します。
IME の制御
小数点の入力問題が解消しても、やはり海外製品だからでしょうか IME を無効にできません。
数値入力専用コントロールですが DoubleUpDown 等の NumericUpDown コントロールで IME を ON にできてしまいます。
通常、WPF で IME を無効にする場合は src. 2 のように InputMethod 添付プロパティを使用します。
1 2 3 4 5 6 7 | <xceed:DoubleUpDown Grid.Column="0" Value="{Binding Height.Value, UpdateSourceTrigger=PropertyChanged}" Validation.ErrorTemplate="{StaticResource ValidationTemplate}" MaxLength="6" VerticalContentAlignment="Center" HorizontalContentAlignment="Right" ShowButtonSpinner="False" Maximum="400" Minimum="0" ParsingNumberStyle="Float" InputMethod.IsInputMethodEnabled="False" /> |
src. 2 のように InputMethod 添付プロパティを追加しても Extended WPF Toolkit の数値入力系コントロールでは IME の On/Off が可能なままです。
(同梱されている AutoSelectTextBox は InputMethod 添付プロパティが反映されます)
但し、全角文字等が入力できてもフォーカスが外れると無効な文字は削除されるので大きな問題にはならないと思います。
Extended WPF Toolkit DateTimePicker コントロール
以下の表はサンプルアプリに追加した Extended WPF Toolkit の DateTimePicker コントロールに設定したプロパティの簡易説明一覧です。
プロパティ名 | 内容 |
---|---|
Value | WPF 標準の DatePicker では SelectedDate プロパティでしたが Value プロパティへ修正する必要があります。 |
Watermark | 以下 fig. 5、6 に表示されている「測定日を選択」のような項目の説明を取得・設定します。 |
ShowButtonSpinner | 入力エリアの UpDown ボタンの表示を取得・設定します。 |
AutoCloseCalendar | true を設定するとドロップダウンカレンダーで日付を選択した後、カレンダーが自動で閉じられます。 false を設定した場合は、日付を選択した後もカレンダーは開いたままです。 |
Format | 入力する日付・時刻のフォーマットを DateTimeFormat 列挙型の内から 1 つ取得・設定します。 設定内容は英語のページですが、Extended WPF Toolkit: New DateTimeUpDown control – Brian Lagunas Blog 等が参考になると思います。 |
TextAlignment | 値の水平位置を取得・設定します。 |
TimePickerVisibility | 時刻入力用 Picker の表示・非表示状態を取得・設定します。 |
DatePicker に Validation を設定した場合の動作
WPF 標準の DatePicker と Extended WPF Toolkit の DateTimePicker の両方とも Nullable<DateTime> の扱いに問題があるようです。
まず WPF 標準の DatePicker では fig. 10 のように画面起動直後に「測定日」を入力せず他のコントロールへフォーカスを移しても【必須入力エラー】が表示されません。
そして少し分かりにくいかもしれませんが fig. 10 の DatePicker は以下のように動作しています。
- 日付をドロップダウンカレンダーから選択
- 日付をクリア
- フォーカスを別のコントロールへ移す
- エラーメッセージ「必須入力です。」が表示される
- 再度日付を選択(1 で選択したのと同じ日付)
- 5 で選択した値が入力エリアにセットされ、エラーメッセージがクリアされる
画面起動直後の LostFocus で Validation が実行されない現象以外は正しい想定通りの動作ですが、これを Extended WPF Toolkit の DateTimePicker に変更して fig. 10 と同じように操作したのが fig. 11 です。
画面起動直後に測定日から他のコントロールへフォーカスを移すとエラーメッセージが表示されないのは WPF 標準の DatePicker と同じですが、fig. 11 の操作でおかしいのは以下の 2 か所です。
- 日付をドロップダウンカレンダーから選択
- 日付をクリア
- フォーカスを別のコントロールへ移す
- × エラーメッセージ「必須入力です。」が表示されない
- ドロップダウンカレンダーで日付選択後
- 日付をクリア
- ドロップダウンカレンダーから 1 で選択したのと同じ日付を選択
- × 7 で選択した値が入力エリアにセットされない
管理人がプロパティか何かの設定を間違えているのかもしれませんが、原因は特定できませんでした。
但し、測定日にバインドしているプロパティへ初期値を設定すると fig.12 のように想定通りに動作するので、初期値に Nullable<DateTime> をセットすることが原因のような気がします。
つまり、Extended WPF Toolkit の DateTimePicker で初期値 null は避けた方が良いと言う事なのかもしれません。
そして WPF 標準の DatePicker、Extended WPF Toolkit の DateTimePicker 両方とも初回ロストフォーカス時に Validation が無視される原因も不明なままなので何か分かったら又記事にまとめたいと思います。
とりあえずサンプルアプリで使用しているコントロールは全て Extended WPF Toolkit のコントロールに置き換えますが、管理人的に無効になる文字は入力できない方が好みなので実際にアプリを作成する場合はやはりカスタムコントロールを作成すると思います。
結局、Extended WPF Toolkit のコントロールを 2 つ紹介しただけで、コントロールの動作に問題があっても解決法の紹介もできていませんが、extra: 4 はこれで終了とします。
ここで紹介したソースコードも他の Prism 入門の episode と同じく GitHub リポジトリ に上げていますが、このエントリの内容は元々 episode: 9 の一部だったため episode: 9 のソリューション に含めています。