⛓️
WPFでTextBoxにdoubleをBindingする
Qiita を退会するにあたって記事の移植をおこないます。
元は2020年02月15日に投稿しました。
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:DoubleTextBox DoubleText="{Binding Double1, UpdateSourceTrigger=PropertyChanged}" />
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
public class DoubleTextBox : TextBox
{
public string DoubleText
{
get => (string)GetValue(DoubleTextProperty);
set => SetValue(DoubleTextProperty, value);
}
public static readonly DependencyProperty DoubleTextProperty =
DependencyProperty.Register(
nameof(DoubleText),
typeof(string),
typeof(DoubleTextBox),
new FrameworkPropertyMetadata(
string.Empty,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
new PropertyChangedCallback(OnDoubleTextChanged),
null,
true,
UpdateSourceTrigger.LostFocus));
private static void OnDoubleTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextBox textBox)
{
var currentText = textBox.Text;
var newText = (string)e.NewValue;
if (currentText == newText)
return;
if (
double.TryParse(currentText, out var currentDouble) &&
double.TryParse(newText, out var newDouble) &&
currentDouble == newDouble
)
return;
textBox.Text = newText;
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
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
を更新しません。
Discussion
string
とバインドしつつ変換をかけるのでも良さそう。