diff --git a/src/System.Windows.Forms.DataVisualization/Utilities/ValueConverter.cs b/src/System.Windows.Forms.DataVisualization/Utilities/ValueConverter.cs
index 08de8112..1266632b 100644
--- a/src/System.Windows.Forms.DataVisualization/Utilities/ValueConverter.cs
+++ b/src/System.Windows.Forms.DataVisualization/Utilities/ValueConverter.cs
@@ -12,157 +12,160 @@
using System.Globalization;
-namespace System.Windows.Forms.DataVisualization.Charting.Utilities
+namespace System.Windows.Forms.DataVisualization.Charting.Utilities;
+
+///
+/// ValueConverter class is used when numeric or DateTime
+/// value needs to be converted to a string using specified format.
+///
+internal static class ValueConverter
{
+ #region Methods
+
///
- /// ValueConverter class is used when numeric or DateTime
- /// value needs to be converted to a string using specified format.
+ /// Converts value to string using specified format.
///
- internal static class ValueConverter
- {
- #region Methods
-
- ///
- /// Converts value to string using specified format.
- ///
- /// Reference to the chart object.
- /// Reference to the object being formatted.
- /// Additional object tag.
- /// Value converted to string.
- /// Format string.
- /// Value type.
- /// Chart element type being formatted.
- public static string FormatValue(
- Chart chart,
- object obj,
- object objTag,
- double value,
- string format,
- ChartValueType valueType,
- ChartElementType elementType)
- {
- format ??= string.Empty;
- string convertionFormat = format;
- string result = string.Empty;
-
- // Make sure value index is part of the format
- if(convertionFormat != null && convertionFormat.Length > 0)
- {
- int bracketIndex = convertionFormat.IndexOf('{', 0);
- if(bracketIndex >= 0)
- {
- while(bracketIndex >= 0)
- {
- // If format is not followed by the value index
- if(!convertionFormat[bracketIndex..].StartsWith("{0:", StringComparison.Ordinal))
- {
- // Check character prior to the bracket
- if(bracketIndex >= 1 && convertionFormat.Substring(bracketIndex - 1, 1) == "{")
- {
- continue;
- }
- else
- {
- // Insert value index in format
- convertionFormat = convertionFormat.Insert(bracketIndex + 1, "0:");
- }
- }
-
- bracketIndex = convertionFormat.IndexOf('{', bracketIndex + 1);
- }
- }
- else
- {
- convertionFormat = "{0:" + convertionFormat + "}";
- }
- }
-
- // Date/time formating
- if (valueType == ChartValueType.DateTime ||
- valueType == ChartValueType.DateTimeOffset ||
- valueType == ChartValueType.Date)
- {
- // Set default format
- if(convertionFormat.Length == 0)
- {
- convertionFormat = "{0:d}";
- if (valueType == ChartValueType.DateTimeOffset)
- convertionFormat += " +0";
- }
-
- // Convert date to string
- result = String.Format(CultureInfo.CurrentCulture, convertionFormat, DateTime.FromOADate(value));
- }
- else if(valueType == ChartValueType.Time)
- {
- // Set default format
- if(convertionFormat.Length == 0)
- {
- convertionFormat = "{0:t}";
- }
-
- // Convert date to string
- result = String.Format(CultureInfo.CurrentCulture, convertionFormat, DateTime.FromOADate(value));
- }
- else
- {
- bool failedFlag = false;
-
- // Set default format
- if(convertionFormat.Length == 0)
- {
- convertionFormat = "{0:G}";
- }
-
- try
- {
- // Numeric value formatting
- result = String.Format(CultureInfo.CurrentCulture,convertionFormat, value);
- }
- catch(FormatException)
- {
- failedFlag = true;
- }
-
- // If numeric formatting failed try to format using decimal number
- if(failedFlag)
- {
- failedFlag = false;
- try
- {
- // Decimal value formatting
- result = String.Format(CultureInfo.CurrentCulture, convertionFormat, (long)value);
- }
- catch (ArgumentNullException)
- {
- failedFlag = true;
- }
- catch (FormatException)
+ /// Reference to the chart object.
+ /// Reference to the object being formatted.
+ /// Additional object tag.
+ /// Value converted to string.
+ /// Format string.
+ /// Value type.
+ /// Chart element type being formatted.
+ public static string FormatValue(
+ Chart chart,
+ object obj,
+ object objTag,
+ double value,
+ string format,
+ ChartValueType valueType,
+ ChartElementType elementType)
+ {
+ format ??= string.Empty;
+ string convertionFormat = format;
+ string result = string.Empty;
+
+ // Make sure value index is part of the format
+ if (convertionFormat != null && convertionFormat.Length > 0)
+ {
+ int bracketIndex = convertionFormat.IndexOf('{', 0);
+ if (bracketIndex >= 0)
+ {
+ while (bracketIndex >= 0)
+ {
+ // If format is not followed by the value index
+ if (!convertionFormat[bracketIndex..].StartsWith("{0:", StringComparison.Ordinal))
{
- failedFlag = true;
+ // Check character prior to the bracket
+ if (bracketIndex >= 1 && convertionFormat.Substring(bracketIndex - 1, 1) == "{")
+ {
+ continue;
+ }
+ else
+ {
+ // Insert value index in format
+ convertionFormat = convertionFormat.Insert(bracketIndex + 1, "0:");
+ }
}
- }
-
- // Return format string as result (literal) if all formatting methods failed
- if(failedFlag)
- {
- result = format;
- }
- }
-
- // For the Reporting Services chart a special number formatting
- // handler may be set and used for all formatting needs.
- if (chart != null)
+
+ bracketIndex = convertionFormat.IndexOf('{', bracketIndex + 1);
+ }
+ }
+ else
+ {
+ convertionFormat = "{0:" + convertionFormat + "}";
+ }
+ }
+
+ // Date/time formating
+ if (valueType == ChartValueType.DateTime ||
+ valueType == ChartValueType.DateTimeOffset ||
+ valueType == ChartValueType.Date)
+ {
+ // Set default format
+ if (convertionFormat.Length == 0)
+ {
+ convertionFormat = "{0:d}";
+ if (valueType == ChartValueType.DateTimeOffset)
+ convertionFormat += " +0";
+ }
+
+ // Convert date to string
+ result = string.Format(CultureInfo.CurrentCulture, convertionFormat, DateTime.FromOADate(value));
+ }
+ else if (valueType == ChartValueType.Time)
+ {
+ // Set default format
+ if (convertionFormat.Length == 0)
{
- // Call number formatter
- FormatNumberEventArgs eventArguments = new FormatNumberEventArgs(value, format, valueType, result, objTag, elementType);
- chart.CallOnFormatNumber(obj, eventArguments);
- result = eventArguments.LocalizedValue;
+ convertionFormat = "{0:t}";
}
- return result;
- }
-
- #endregion
- }
+ // Convert date to string
+ result = string.Format(CultureInfo.CurrentCulture, convertionFormat, DateTime.FromOADate(value));
+ }
+ else
+ {
+ bool failedFlag = false;
+
+ // Set default format
+ if (convertionFormat.Length == 0)
+ {
+ convertionFormat = "{0:G}";
+ }
+
+ try
+ {
+ // Numeric value formatting
+ // Workaround for "-0" label due to Floating-Point parsing changes in .NET Core 3. See https://devblogs.microsoft.com/dotnet/floating-point-parsing-and-formatting-improvements-in-net-core-3-0/
+ if (value == 0d && double.IsNegative(value))
+ result = string.Format(CultureInfo.CurrentCulture, convertionFormat, 0d);
+ else
+ result = string.Format(CultureInfo.CurrentCulture, convertionFormat, value);
+ }
+ catch (FormatException)
+ {
+ failedFlag = true;
+ }
+
+ // If numeric formatting failed try to format using decimal number
+ if (failedFlag)
+ {
+ failedFlag = false;
+ try
+ {
+ // Decimal value formatting
+ result = string.Format(CultureInfo.CurrentCulture, convertionFormat, (long)value);
+ }
+ catch (ArgumentNullException)
+ {
+ failedFlag = true;
+ }
+ catch (FormatException)
+ {
+ failedFlag = true;
+ }
+ }
+
+ // Return format string as result (literal) if all formatting methods failed
+ if (failedFlag)
+ {
+ result = format;
+ }
+ }
+
+ // For the Reporting Services chart a special number formatting
+ // handler may be set and used for all formatting needs.
+ if (chart != null)
+ {
+ // Call number formatter
+ FormatNumberEventArgs eventArguments = new FormatNumberEventArgs(value, format, valueType, result, objTag, elementType);
+ chart.CallOnFormatNumber(obj, eventArguments);
+ result = eventArguments.LocalizedValue;
+ }
+
+ return result;
+ }
+
+ #endregion
}