J'essaie d'afficher une décimale formatée dans un TextBox en utilisant la liaison de données dans WPF.
Objectifs
Objectif 1 : Lors de la définition d'une propriété décimale dans le code, afficher 2 décimales dans la TextBox.
Objectif 2 : Lorsqu'un utilisateur interagit avec (tape dans) la TextBox, ne le mettez pas en colère.
Objectif 3 : Les liaisons doivent mettre à jour la source sur PropertyChanged.
Tentatives
Tentative 1 : Pas de formatage.
Ici, nous partons presque de zéro.
<TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" />
Viole l'objectif 1. SomeDecimal = 4.5
affichera "4.50000" dans la boîte de texte.
Tentative 2 : Utilisez StringFormat dans le Binding.
<TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}" />
Viole l'objectif 2. Disons que SomeDecimal est 2.5, et que la TextBox affiche "2.50". Si nous sélectionnons tout et tapons "13.5", nous nous retrouvons avec "13.5.00" dans la zone de texte parce que le formateur insère "utilement" les décimales et les zéros.
Tentative 3 : utiliser la MaskedTextBox de l'Extended WPF Toolkit.
http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox
Si je lis correctement la documentation, le masque ##0.00 signifie "deux chiffres facultatifs, suivis d'un chiffre obligatoire, d'un point décimal et de deux autres chiffres obligatoires". Cela m'oblige à dire "le plus grand nombre possible qui peut entrer dans ce champ de texte est 999.99" mais disons que cela me convient.
<xctk:MaskedTextBox Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" Mask="##0.00" />
Viole l'objectif 2. La boîte de texte commence par ___.__
et en le sélectionnant et en tapant 5,75, on obtient 575.__
. La seule façon d'obtenir 5.75 est de sélectionner le TextBox et de taper <space><space>5.75
.
Tentative 4 : utiliser le spinner DecimalUpDown de l'Extended WPF Toolkit.
http://wpftoolkit.codeplex.com/wikipage?title=DecimalUpDown
<xctk:DecimalUpDown Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" FormatString="F2" />
Viole l'objectif 3. DecimalUpDown ignore heureusement UpdateSourceTrigger=PropertyChanged. L'un des coordinateurs de la page Codeplex Extended WPF Toolkit suggère un ControlTemplate modifié à l'adresse suivante http://wpftoolkit.codeplex.com/discussions/352551/ . Cela satisfait l'objectif 3, mais viole l'objectif 2, en présentant le même comportement que dans la tentative 2.
Tentative 5 : Utiliser des matrices de style, n'utiliser le formatage que si l'utilisateur n'édite pas.
Liaison à un double avec StringFormat sur une TextBox
Même si celui-ci répondait à ces trois objectifs, je ne voudrais pas l'utiliser. (A) Les zones de texte deviennent 12 lignes chacune au lieu de 1, et mon application contient de très nombreuses zones de texte. (B) Toutes mes zones de texte ont déjà un attribut Style qui pointe vers une StaticResource globale qui définit la Marge, la Hauteur, et d'autres choses. (C) Vous avez peut-être remarqué que le code ci-dessous définit deux fois le binding Path, ce qui viole le principe DRY.
<TextBox>
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Text" Value="{Binding Path=SomeDecimal, StringFormat=F2}" />
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Text" Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Toutes ces choses inconfortables mises à part...
Viole l'objectif 2. Tout d'abord, en cliquant sur une TextBox qui affiche "13.50", celle-ci affiche soudainement "13.5000", ce qui est inattendu. Deuxièmement, si je commence par une TextBox vide, et que je tape "13.50", la TextBox contiendra "1350". Je ne peux pas expliquer pourquoi, mais appuyer sur la touche de point n'insère pas les décimales si le curseur est à l'extrémité droite de la chaîne dans la TextBox. Si le TextBox contient une chaîne de longueur > 0, et que je repositionne le curseur n'importe où sauf à l'extrémité droite de la chaîne, je peux alors insérer les décimales.
Tentative 6 : le faire moi-même.
Je suis sur le point de m'embarquer dans un voyage de souffrance, soit en sous-classant TextBox, soit en créant une propriété attachée, et en écrivant le code de formatage moi-même. Ce sera plein de manipulations de chaînes de caractères, et provoquera une importante perte de cheveux.
Quelqu'un a-t-il des suggestions pour le formatage des décimales liées aux zones de texte qui satisfasse tous les objectifs ci-dessus ?