格式为 wpf 中没有尾随零的货币 xaml

Format as currency with no trailing zeroes in wpf xaml

假设我们有一个视图模型 属性 MyMoney。如何在其视图 xaml 中将其格式化为没有尾随零的货币?

例如:

MyMoney = 1; //
MyMoney = 1.2 //.2

我在 xaml 中尝试了以下方法(例如 <TextBox Text="{Binding MyMoney, StringFormat=..."/>),但它不满足所有条件:

StringFormat=C 显示货币,但也显示尾随零。
StringFormat=C0 显示货币但只显示整数。
StringFormat={}{0:0.##} 不显示尾随零但不显示为货币。
StringFormat={}{0:[=17=].##} 不显示尾随零但硬编码 $。我们应该能够满足当前 locale/culture 的货币。

可能你会知道字符串格式的 "C" 根据你本地 machine.However 设置的 locale/culture 来回答你的问题,我建议把尾随将 属性 级别的删除代码清零,并保持 xaml 级别的字符串格式与 possible.for 一样简单,例如

在 xaml 级别:

  <TextBox x:Name="TextBox_Curr" Height="50" Text="{Binding Money,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay,StringFormat={}{0:C}}" Margin="120,134,156,135"/>

在模型级别(只是原始代码):

  private decimal _money;
        public decimal Money
        {
            get { return _money; }
            set {

                 _money = value;
                _money.ToString("0.##");

                 NotifyPropertyChanged("Money"); }
        }

它对我有用,而 运行 示例代码。

此外,如果您不想更改系统设置,您可能会选择强制文化设置。

public static class Cultures
{
    public static readonly CultureInfo UnitedKingdom = 
        CultureInfo.GetCultureInfo("en-GB");
}
Then:

Money.ToString("C", Cultures.UnitedKingdom)

我认为您非常需要在这里使用转换器,因为需要删除尾随零。 这可能需要更多的工作但是:

using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;

namespace wpf_99
{
public class CurrencyFormatConverter : MarkupExtension, IValueConverter
{
// public double Multiplier { get; set; } You could pass parameters to properties.

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return CultureInfo.CurrentCulture.NumberFormat.CurrencySymbol + System.Convert.ToDecimal(value).ToString("0.##");
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string input = value.ToString();
        if(!char.IsDigit(input[0]))
        {
            input= input.Substring(1);
        }
        if(input.Length == 0)
        {
            return 0;
        }
        return Decimal.Parse(input);
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}
}

用法

<TextBox Text="{Binding Money,UpdateSourceTrigger=PropertyChanged, Converter={local:CurrencyFormatConverter}}"/>

首先,我想感谢@Andy 的 ,这让我使用了 IValueConverter.

我正在发布我的解决方案,它具有以下优势:

  1. 利用 C# 的 "C" format specifier

    一个。考虑负值(例如 -1 --> ()

    b。迎合变流locale/culture

  2. 绑定到多种数据类型(decimaldoubleint 等)。

  3. Return DependencyProperty.UnsetValue when ConvertBack is unable to produce a value.

以上所有内容都遵循 StringFormat=c 在 wpf 中的行为方式(例如在 TextBox 中),除了转换器会根据需要删除尾随零。


public class CurrencyFormatConverter : MarkupExtension, IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
        System.Convert.ToDecimal(value).ToCurrency(culture);

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        switch (Type.GetTypeCode(targetType))
        {
            case TypeCode.Decimal:
                return Decimal.TryParse(value.ToString(), NumberStyles.Currency, culture, out var @decimal)
                    ? @decimal
                    : DependencyProperty.UnsetValue;

            case TypeCode.Double:
                return Double.TryParse(value.ToString(), NumberStyles.Currency, culture, out var @double)
                    ? @double
                    : DependencyProperty.UnsetValue;

            case TypeCode.Int16:
                return Int16.TryParse(value.ToString(), NumberStyles.Currency, culture, out var int16)
                    ? int16
                    : DependencyProperty.UnsetValue;

            case TypeCode.Int32:
                return Int32.TryParse(value.ToString(), NumberStyles.Currency, culture, out var int32)
                    ? int32
                    : DependencyProperty.UnsetValue;

            case TypeCode.Int64:
                return Int64.TryParse(value.ToString(), NumberStyles.Currency, culture, out var int64)
                    ? int64
                    : DependencyProperty.UnsetValue;

            case TypeCode.Single:
                return Single.TryParse(value.ToString(), NumberStyles.Currency, culture, out var single)
                    ? single
                    : DependencyProperty.UnsetValue;

            case TypeCode.UInt16:
                return UInt16.TryParse(value.ToString(), NumberStyles.Currency, culture, out var uint16)
                    ? uint16
                    : DependencyProperty.UnsetValue;

            case TypeCode.UInt32:
                return UInt32.TryParse(value.ToString(), NumberStyles.Currency, culture, out var uint32)
                    ? uint32
                    : DependencyProperty.UnsetValue;

            case TypeCode.UInt64:
                return UInt64.TryParse(value.ToString(), NumberStyles.Currency, culture, out var uint64)
                    ? uint64
                    : DependencyProperty.UnsetValue;

            default:
                throw new NotSupportedException($"Converting currency string to target type {targetType} is not supported.");
        }
    }

    public override object ProvideValue(IServiceProvider serviceProvider) => this;
}

More info on ToCurrency here

public static class DecimalExtensions
{
    /// <summary>
    ///     Converts a numeric value to its equivalent currency string representation using the specified culture-specific format information.
    /// </summary>
    /// <param name="value">The value to be converted.</param>
    /// <param name="provider">An object that supplies culture-specific formatting information.</param>
    /// <returns>The currency string representation of the value as specified by <paramref name="provider" />.</returns>
    public static string ToCurrency(this decimal value, IFormatProvider provider) =>
        /// Use "1" (or "-1" if value is negative)
        /// as a placeholder for the actual value.
        (value < 0 ? -1 : 1)

        /// Format as a currency using the "C" format specifier.
        .ToString("C0", provider)

        /// Convert the absolute value to its string representation
        /// then replace the placeholder "1".
        /// We used absolute value since the negative sign
        /// is already converted to its string representation
        /// using the "C" format specifier.
        .Replace("1", Math.Abs(value).ToString("#,0.############################", provider));
}