Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I format a decimal bound to TextBox without angering my users?
    primarykey
    data
    text
    <p>I'm trying to display a formatted decimal in a TextBox using data binding in WPF.</p> <h2>Goals</h2> <p>Goal 1: When setting a decimal property in code, display 2 decimal places in the TextBox.</p> <p>Goal 2: When a user interacts with (types in) the TextBox, don't piss him/her off.</p> <p>Goal 3: Bindings must update source on PropertyChanged.</p> <h2>Attempts</h2> <p><strong><em>Attempt 1: No formatting.</em></strong></p> <p>Here we're starting nearly from scratch.</p> <pre><code>&lt;TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" /&gt; </code></pre> <p>Violates Goal 1. <code>SomeDecimal = 4.5</code> will show "4.50000" in the TextBox.</p> <p><strong><em>Attempt 2: Use StringFormat in the Binding.</em></strong></p> <pre><code>&lt;TextBox Text="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged, StringFormat=F2}" /&gt; </code></pre> <p>Violates Goal 2. Say SomeDecimal is 2.5, and the TextBox is displaying "2.50". If we select all and type "13.5" we end up with "13.5.00" in the TextBox because the formatter "helpfully" inserts decimals and zeros.</p> <p><strong><em>Attempt 3: use Extended WPF Toolkit's MaskedTextBox.</em></strong></p> <p><a href="http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox" rel="nofollow noreferrer">http://wpftoolkit.codeplex.com/wikipage?title=MaskedTextBox</a></p> <p>Assuming I'm reading the documentation correctly, the mask ##0.00 means "two optional digits, followed by a required digit, a decimal point, and two more required digits. This forces me to say "the largest possible number that can go into this TextBox is 999.99" but let's say I'm ok with that.</p> <pre><code>&lt;xctk:MaskedTextBox Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" Mask="##0.00" /&gt; </code></pre> <p>Violates Goal 2. The TextBox starts with <code>___.__</code> and selecting it and typing 5.75 yields <code>575.__</code>. The only way to get 5.75 is to select the TextBox and type <code>&lt;space&gt;&lt;space&gt;5.75</code>.</p> <p><strong><em>Attempt 4: use Extended WPF Toolkit's DecimalUpDown spinner.</em></strong></p> <p><a href="http://wpftoolkit.codeplex.com/wikipage?title=DecimalUpDown" rel="nofollow noreferrer">http://wpftoolkit.codeplex.com/wikipage?title=DecimalUpDown</a></p> <pre><code>&lt;xctk:DecimalUpDown Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" FormatString="F2" /&gt; </code></pre> <p>Violates Goal 3. DecimalUpDown happily ignores UpdateSourceTrigger=PropertyChanged. One of the Coordinators on the Extended WPF Toolkit Codeplex page suggests a modified ControlTemplate at <a href="http://wpftoolkit.codeplex.com/discussions/352551/" rel="nofollow noreferrer">http://wpftoolkit.codeplex.com/discussions/352551/</a>. This satisfies Goal 3, but violates Goal 2, exhibiting the same behavior as in Attempt 2.</p> <p><strong><em>Attempt 5: Using style datatriggers, only use formatting if user is not editing.</em></strong></p> <p><a href="https://stackoverflow.com/questions/8183922">Binding to a double with StringFormat on a TextBox</a></p> <p>Even if this one satisfied all three goals, I wouldn't want to use it. (A) Textboxes become 12 lines each instead of 1, and my application contains many, many textboxes. (B) All my textboxes already have a Style attribute which points to a global StaticResource which sets Margin, Height, and other things. (C) You may have noticed the code below sets the binding Path twice, which violates the DRY principal.</p> <pre><code>&lt;TextBox&gt; &lt;TextBox.Style&gt; &lt;Style TargetType="{x:Type TextBox}"&gt; &lt;Setter Property="Text" Value="{Binding Path=SomeDecimal, StringFormat=F2}" /&gt; &lt;Style.Triggers&gt; &lt;Trigger Property="IsFocused" Value="True"&gt; &lt;Setter Property="Text" Value="{Binding Path=SomeDecimal, UpdateSourceTrigger=PropertyChanged}" /&gt; &lt;/Trigger&gt; &lt;/Style.Triggers&gt; &lt;/Style&gt; &lt;/TextBox.Style&gt; &lt;/TextBox&gt; </code></pre> <p>All these uncomfortable things aside...</p> <p>Violates Goal 2. First, clicking on a TextBox which displays "13.50" suddenly makes it display "13.5000", which is unexpected. Second, if starting with a blank TextBox, and I type "13.50", the TextBox will contain "1350". I can't explain why, but pressing the period key doesn't insert decimals if the cursor is at the right end of the string in the TextBox. If the TextBox contains a string with length > 0, and I reposition the cursor to anywhere except the right end of the string, I can then insert decimal points.</p> <p><strong><em>Attempt 6: Do it myself.</em></strong></p> <p>I'm about to embark on a jouney of pain and suffering, by either subclassing TextBox, or creating an attached property, and writing the formatting code myself. It will be full of string manipulation, and cause substantial hairloss.</p> <hr> <p>Does anyone have any suggestions for formatting decimals bound to textboxes that satisfies all the above goals?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload