Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NumericUpDown StringFormat doesn't handle percentages correctly. #3376

Closed
SteffanDonal opened this issue Nov 22, 2018 · 11 comments · Fixed by #3678
Closed

NumericUpDown StringFormat doesn't handle percentages correctly. #3376

SteffanDonal opened this issue Nov 22, 2018 · 11 comments · Fixed by #3678
Labels
Milestone

Comments

@SteffanDonal
Copy link

There's strange behaviour happening with NumericUpDown's StringFormat property, particularly around percentages.

First it looks like the P, % & format specifiers are being ignored, but when adding those same symbols outside of a format item, the numbers appear to be divided by 100 or 1000.

I do remember more frustrating issues before however - particularly with editing values. Previously, the numbers would look correct initially. After editing, the real value would be multiplied repeatedly.

To Reproduce:

Case 1:

  1. Set NumericUpDown.StringFormat to {0:0.00%} or 0.00%
  2. Set NumericUpDown.Value to 0.25
  3. See that the label now shows 0.25% (expected 25.00%)

Case 2:

  1. Set NumericUpDown.StringFormat to {0:0.00‰} or 0.00‰
  2. Set NumericUpDown.Value to 0.25
  3. See that the label now shows 0.25‰ (expected 250.00%)

Case 3:

  1. Set NumericUpDown.StringFormat to {0:0.0000}%
  2. Set NumericUpDown.Value to 0.25
  3. See that the label now shows 0.0025% (expected 0.2500%)
  4. Additionally, editing this number causes further division to the real value.

Case 4:

  1. Set NumericUpDown.StringFormat to {0:0.00000}‰
  2. Set NumericUpDown.Value to 0.25
  3. See that the label now shows 0.00025‰ (expected 0.25000‰)
  4. Additionally, editing this number causes further division to the real value.

Case 5:

  1. Set NumericUpDown.StringFormat to P
  2. Set NumericUpDown.Value to 0.25
  3. See that the label now shows 0.25% (expected 25.00 %)

Environment:

  • MahApps.Metro version 2.0.0-alpha0083
  • OS: Win10 1803
  • Visual Studio 2017 15.7.1
  • .NET Framework 4.6.2
@punker76 punker76 added the Bug label Nov 25, 2018
@punker76 punker76 added this to the 2.0.0 milestone Nov 25, 2018
@ckaeser-lsi
Copy link

I have an issue in the same direction. We use Numerics string format to display inline units for inputs.

Having a string format containing a "p" or "P" results in a display of percentage
e.g StringFormat="{}{0:G3} mPa·s" input "0.986" displays as "0.00986 mPa·s"

@mgnslndh
Copy link
Contributor

I've investigated this issue and these are my findings:

The current implementation in NumericUpDown seems to have special handling of format specifiers such as P, % and ‰. The .NET formatting rules equals 1 to "100%" or "1000%" using the P specifier. In case these format specifiers are used in NumericUpDown the value will be divided in such a way that the .NET formatting rules will be ignored.

Example:
string.Format("{0:P0}", 1); will become "100%" but NumericUpDown will format the value 1 as 1% using that same format.

It seems to me that @SteffanDonal is expecting the default behaviour in .NET but this is not how NumericUpDown works right now. I can see the usefulness of both variations of how to format P, % and ‰

We could support both variations by adding a property to NumericUpDown such as UseCustomFormatting with the default value of true. This would preserve backwards compatibility. Setting UseCustomFormatting to false would disable the division for preserving the value and the format will be exactly like described in the documentation for the P specifier. If you have suggestions for a better naming of this property, please let me know.

I can provide a PR for this if we want to make NumericUpDown support both the current custom formatting of P, % and ‰ and the native formatting provided by the framework.

@ckaeser-lsi your issue is actually a different bug where NumericUpDown formatting does not take into account where the specifier is used. I have a fix for your issue and will submit it as a PR. Not sure if @punker76 wants us to raise a separate issue and submit the PR there or here. Case 3 & 4 above is related to this issue.

@timunie
Copy link
Collaborator

timunie commented Sep 20, 2019

Hi @mgnslndh ,

did you get the standard .NET-Method to work? I tried to change the behaviour for myself in the past, but then i got some strange behaviour. I thought that this was the reason for this implementation. Since then I use a converter which works quite nice.

Happy coding,
Tim

@mgnslndh
Copy link
Contributor

@timunie I haven't tried making it work like .NET default formatting yet. But I guess there might be some issues to work through.

@punker76 have we decided that the current behavior is a bug?

This is my perception of this issue. Is it correct?

Current behavior

Using the P format specifier and entering a value of 100 should result in a value of 100.

Desired behavior

Using the P format specifier and entering a value of 100 should result in a value of 1.

For users that still want the current behavior they could change the formatting to use something like "{}{0} %" which gives them the percentage sign but does not affect the value.

@timunie
Copy link
Collaborator

timunie commented Oct 15, 2019

@mgnslndh From my point of view I can confirm that this is what I was expecting when I used the control the first time. But I don't mind if it will not be fixed.

Happy coding
Tim

@punker76
Copy link
Member

punker76 commented Nov 6, 2019

@mgnslndh @timunie I think we should change the behavior to the .Net default formatting. This should not confuse new users and doesn't make anything unusual you wouldn't expect.


>> value: 100  => P      => 10,000.00 %
>> value: 1    => P      => 100.00 %
>> value: 0.1  => P      => 10.00 %
>> value: 0.01 => P      => 1.00 %

>> value: 100  => %      => 100%
>> value: 1    => %      => 1%
>> value: 0.1  => %      => 0.1%
>> value: 0.01 => %      => 0.01%

>> value: 100  => 0%     => 10000%
>> value: 1    => 0%     => 100%
>> value: 0.1  => 0%     => 10%
>> value: 0.01 => 0%     => 1%

>> value: 100  => 0.0%   => 10000.0%
>> value: 1    => 0.0%   => 100.0%
>> value: 0.1  => 0.0%   => 10.0%
>> value: 0.01 => 0.0%   => 1.0%

>> value: 100  => 0.000% => 10000.000%
>> value: 1    => 0.000% => 100.000%
>> value: 0.1  => 0.000% => 10.000%
>> value: 0.01 => 0.000% => 1.000%
using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
  public static void Main()
  {
    Console.WriteLine($">> value: 100  => P      => {100:P}");
    Console.WriteLine($">> value: 1    => P      => {1:P}");
    Console.WriteLine($">> value: 0.1  => P      => {0.1:P}");
    Console.WriteLine($">> value: 0.01 => P      => {0.01:P}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => %      => {100}%");
    Console.WriteLine($">> value: 1    => %      => {1}%");
    Console.WriteLine($">> value: 0.1  => %      => {0.1}%");
    Console.WriteLine($">> value: 0.01 => %      => {0.01}%");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0%     => {100:0%}");
    Console.WriteLine($">> value: 1    => 0%     => {1:0%}");
    Console.WriteLine($">> value: 0.1  => 0%     => {0.1:0%}");
    Console.WriteLine($">> value: 0.01 => 0%     => {0.01:0%}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0.0%   => {100:0.0%}");
    Console.WriteLine($">> value: 1    => 0.0%   => {1:0.0%}");
    Console.WriteLine($">> value: 0.1  => 0.0%   => {0.1:0.0%}");
    Console.WriteLine($">> value: 0.01 => 0.0%   => {0.01:0.0%}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0.000% => {100:0.000%}");
    Console.WriteLine($">> value: 1    => 0.000% => {1:0.000%}");
    Console.WriteLine($">> value: 0.1  => 0.000% => {0.1:0.000%}");
    Console.WriteLine($">> value: 0.01 => 0.000% => {0.01:0.000%}");
  }
}

@punker76
Copy link
Member

punker76 commented Nov 6, 2019

@mgnslndh @timunie The same with ‰

>> value: 100  => ‰      => 100‰
>> value: 1    => ‰      => 1‰
>> value: 0.1  => ‰      => 0.1‰
>> value: 0.01 => ‰      => 0.01‰

>> value: 100  => 0‰     => 100000‰
>> value: 1    => 0‰     => 1000‰
>> value: 0.1  => 0‰     => 100‰
>> value: 0.01 => 0‰     => 10‰

>> value: 100  => 0.0‰   => 100000.0‰
>> value: 1    => 0.0‰   => 1000.0‰
>> value: 0.1  => 0.0‰   => 100.0‰
>> value: 0.01 => 0.0‰   => 10.0‰

>> value: 100  => 0.000‰ => 100000.000‰
>> value: 1    => 0.000‰ => 1000.000‰
>> value: 0.1  => 0.000‰ => 100.000‰
>> value: 0.01 => 0.000‰ => 10.000‰
using System;
using System.Collections.Generic;
using System.Linq;

public class Program
{
  public static void Main()
  {
    Console.WriteLine($">> value: 100  => ‰      => {100}");
    Console.WriteLine($">> value: 1    => ‰      => {1}");
    Console.WriteLine($">> value: 0.1  => ‰      => {0.1}");
    Console.WriteLine($">> value: 0.01 => ‰      => {0.01}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0‰     => {100:0‰}");
    Console.WriteLine($">> value: 1    => 0‰     => {1:0‰}");
    Console.WriteLine($">> value: 0.1  => 0‰     => {0.1:0‰}");
    Console.WriteLine($">> value: 0.01 => 0‰     => {0.01:0‰}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0.0‰   => {100:0.0‰}");
    Console.WriteLine($">> value: 1    => 0.0‰   => {1:0.0‰}");
    Console.WriteLine($">> value: 0.1  => 0.0‰   => {0.1:0.0‰}");
    Console.WriteLine($">> value: 0.01 => 0.0‰   => {0.01:0.0‰}");
    Console.WriteLine();
    Console.WriteLine($">> value: 100  => 0.000‰ => {100:0.000‰}");
    Console.WriteLine($">> value: 1    => 0.000‰ => {1:0.000‰}");
    Console.WriteLine($">> value: 0.1  => 0.000‰ => {0.1:0.000‰}");
    Console.WriteLine($">> value: 0.01 => 0.000‰ => {0.01:0.000‰}");
  }
}

@timunie
Copy link
Collaborator

timunie commented Nov 6, 2019

Hi @punker76 ,

what will happen if the user enters 100 and omits the % when using StringFormat 'P' ? When I wanted to change NumericUpDown to handle this that was my point where I did not get a solution. My users are using Excel all the day and Excel handles this if the cell is already marked as percentage.

Happy coding
Tim

@punker76
Copy link
Member

punker76 commented Nov 6, 2019

@mgnslndh @timunie Here we go... I'll make a PR tonight

mahapps_numericupdown

punker76 added a commit that referenced this issue Nov 6, 2019
The current behavior for e.g. percentage text input with StringFotmat like P0 or {0:0.00%} converts the input one-to-one to the value:

100% = 100

This is not what the user expects, because the .Net default works different:

100% = 1

So this PR changes this behavior to the .Net default one.
@mgnslndh
Copy link
Contributor

mgnslndh commented Nov 6, 2019

Make sure you have a test for the following combination

StringFormat={}{0}%
Value=100
Text=100%

This would be how you get the percentage sign without any conversion.

Other than that, looking good @punker76

@punker76
Copy link
Member

punker76 commented Nov 7, 2019

Make sure you have a test for the following combination

StringFormat={}{0}%
Value=100
Text=100%

This would be how you get the percentage sign without any conversion.

Other than that, looking good @punker76

image

punker76 added a commit that referenced this issue Nov 8, 2019
The current behavior for e.g. percentage text input with StringFotmat like P0 or {0:0.00%} converts the input one-to-one to the value:

100% = 100

This is not what the user expects, because the .Net default works different:

100% = 1

So this PR changes this behavior to the .Net default one.
punker76 added a commit that referenced this issue Nov 9, 2019
punker76 added a commit that referenced this issue Nov 9, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
The current behavior for e.g. percentage text input with StringFotmat like P0 or {0:0.00%} converts the input one-to-one to the value:

100% = 100

This is not what the user expects, because the .Net default works different:

100% = 1

So this PR changes this behavior to the .Net default one.
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
amkuchta pushed a commit to amkuchta/MahApps.Metro that referenced this issue Nov 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

5 participants