WPFでTextBoxにdoubleをBindingすると
- 文字の末尾に小数点を入力できない
1.002の2を消すと1.00ではなく1になる
などの動作になります。
これはBindingしている値をTextBoxにも即反映させるという動作になっているからです。
1.002の末尾の2を消した際の動作は下記のようになります。
Textが1.00に更新- Binding Sourceのdoubleが
(double)1に更新 Textが1に更新
雑な解決
起動時に
App.xaml.cs
System.Windows.FrameworkCompatibilityPreferences.KeepTextBoxDisplaySynchronizedWithTextProperty=false;と設定すれば解決です。
Bindingしている値をTextBoxにも即反映させないようにします。
.NET Framework 4.5以前はこれがデフォルトです。
解決
Textプロパティを更新する前に別のプロパティでチェックを行うことで期待する動作を実現します。
Textは設定せずにDoubleTextのみを使います。
<myControl:DoubleTextBoxDoubleText="{Binding Double1, UpdateSourceTrigger=PropertyChanged}"/>usingSystem;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Data;publicclassDoubleTextBox:TextBox{publicstringDoubleText{get=>(string)GetValue(DoubleTextProperty);set=>SetValue(DoubleTextProperty,value);}publicstaticreadonlyDependencyPropertyDoubleTextProperty=DependencyProperty.Register(nameof(DoubleText),typeof(string),typeof(DoubleTextBox),newFrameworkPropertyMetadata(string.Empty,FrameworkPropertyMetadataOptions.BindsTwoWayByDefault|FrameworkPropertyMetadataOptions.Journal,newPropertyChangedCallback(OnDoubleTextChanged),null,true,UpdateSourceTrigger.LostFocus));privatestaticvoidOnDoubleTextChanged(DependencyObjectd,DependencyPropertyChangedEventArgse){if(disTextBoxtextBox){varcurrentText=textBox.Text;varnewText=(string)e.NewValue;if(currentText==newText)return;if(double.TryParse(currentText,outvarcurrentDouble)&&double.TryParse(newText,outvarnewDouble)&¤tDouble==newDouble)return;textBox.Text=newText;}}protectedoverridevoidOnTextChanged(TextChangedEventArgse){base.OnTextChanged(e);this.DoubleText=this.Text;}}動作の解説
これによって、1.002の末尾の2を消した際の動作は下記のようになります。
Textが1.00に更新DoubleTextが1.00に更新- Binding Sourceのdoubleが
(double)1に更新 DoubleTextが1に更新1と1.00はともにdouble値として等しいのでTextは更新されない
Textが更新された場合の動作
キーの入力などでTextが更新されたときはその値がそのままDoubleTextに反映されます。
Binding Sourceへも同様に反映されます。
DoubleText(あるいはBinding Source)が更新された場合の動作
基本的にはTextに反映されます。
ただし、DoubleTextとTextをそれぞれdoubleに変換して同じ値になる場合はTextを更新しません。