7

I am using WPF's TextBox with a binding on the Text property to a double on my ViewModel.

My XAML looks like this:

<TextBox Text="{Binding Path=MyDoubleValue, StringFormat=N2, UpdateSourceTrigger=PropertyChanged}" />

Unfortunately when I switch UpdateSourceTrigger to PropertyChanged and type value 12345, I get 12,354.00 (EDIT: notice the 5 before the 4). This is a result of keeping cursor in the same place after adding , between 2 and 3 by the .NET formatter.

How can I use StringFormat with UpdateSourceTrigger set to PropertyChanged?

Note: This is only happening in .NET 4.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
bartosz.lipinski
  • 2,627
  • 2
  • 21
  • 34
  • 1
    Is 12,345.00 not what you'd expect when using StrngFormat N2? What do you expect? – Jens Nov 18 '11 at 14:28
  • Yes exactly, but instead of getting that I have 12,354.00. – bartosz.lipinski Nov 18 '11 at 14:29
  • The format string will not cause the digits to switch like that, there must be something else going on – Ben Robinson Nov 18 '11 at 14:33
  • 3
    @BenRobinson have you tried it? It's surprising and buggy. – Ray Nov 18 '11 at 14:38
  • Not in WPF but 12345.ToString("N2") returns 12,345.00. Are you saying there is some weird string.format bug that is specific to WPF? – Ben Robinson Nov 18 '11 at 14:47
  • Interestingly the bug still occurs if you specify a converter and get the converter to apply the formatting. In the Convert method I have this code: `return string.Format("{0:N2}", value);` – ChrisWay Nov 18 '11 at 14:48
  • OK, with the update i think i understand what you are saying, it is not really a format bug, it is just that when it formats the string to add the thousand separator as you are typing it MOVES the cursor so you end up typing the last 5 before the 4 – Ben Robinson Nov 18 '11 at 14:50
  • @BenRobinson I know how stringformat is working and question is specific to WPF 4 – bartosz.lipinski Nov 18 '11 at 14:50

1 Answers1

10

Usually you don't want UpdateSourceTrigger to be PropertyChanged on a TextBox.Text binding because this triggers the Validation and Change notification every time a key is pressed.

If you are doing this only so that if the user hits Enter it will save the value before processing the save command, then I'd suggest hooking into the PreviewKeyDown event and manually updating the source if the key pressed was Enter (Usually I make this an AttachedProperty)

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.Enter)
    {
        var obj = sender as UIElement;
        BindingExpression textBinding = BindingOperations.GetBindingExpression(
            obj, TextBox.TextProperty);

        if (textBinding != null)
            textBinding.UpdateSource();
    }
}

But with that being said, if you still wanted to use UpdateSourceTrigger=PropertyChanged, then consider using the formatting when displaying the value, but remove it while the user is editing it.

<TextBox>
    <TextBox.Style>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Text" Value="{Binding Path=MyDoubleValue, StringFormat=N2}" />
            <Style.Triggers>
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Text" Value="{Binding Path=MyDoubleValue, UpdateSourceTrigger=PropertyChanged}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>
Rachel
  • 130,264
  • 66
  • 304
  • 490
  • Do you have any idea how to achieve something similar with converters? The perfect solution would be to have a converter which is doing formatting only if control is not focused – bartosz.lipinski Nov 21 '11 at 08:00
  • @baalazamon You could create a StringFormat multi-converter which returns your `value.ToString(converterParameter)` if the control `IsFocused`, however I think DataTriggers is a better way to go in this case – Rachel Nov 21 '11 at 12:36
  • 4
    For some reason, using this solution, if I type "2.5" into a blank `TextBox` I get "25", the decimal isn't appearing. If I reposition the cursor to anywhere except further right, then I can type decimals. – epalm Jul 13 '12 at 18:58
  • 1
    @epalm the reason is logical. When sourceTrigger=PropChanged the text is evaluated as you type it. When you type "2." it will apply the double format and give you "2". This effectively means you can't type a decimal without positioning your cursor away from the right edge. – Bill Tarbell Mar 12 '14 at 18:57
  • Thanks Rachel, your second solution did the trick for me. @epalm & @BillTarbell I had the same issue. This can be fixed by adding a `Delay=350` to the `UpdateSourceTrigger=PropertyChanged Binding`. (350 can be replaced with any time in ms). – Kevin Cruijssen Sep 16 '15 at 09:58