在wpf xaml中

时间:2018-12-14 16:52:46

标签: c# wpf xaml string-formatting currency-formatting

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

例如:

MyMoney = 1; //$1
MyMoney = 1.2 //$1.2

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

StringFormat=C显示货币,但尾随零。
StringFormat=C0显示货币,但仅显示整数。
StringFormat={}{0:0.##}不显示尾随零,但不显示货币。
StringFormat={}{0:$0.##}不显示尾随零,而是硬编码的$。我们应该能够满足当前语言环境/文化的货币要求。

3 个答案:

答案 0 :(得分:2)

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

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}}"/>

答案 1 :(得分:0)

可能您会知道字符串格式的“ C”是根据本地计算机上的语言环境/区域性设置起作用的。但是,回答您的问题,我建议将尾随零的删除代码放在属性级别并保持在xaml级别上的字符串格式应尽可能简单。例如

在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)

答案 2 :(得分:0)

首先,我想感谢@Andy的his answer,这使我使用了IValueConverter

我发布的解决方案具有以下优点:

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

    a。考虑负值(例如-1 --> ($1)

    b。适应当前不同的语言环境/文化

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

  3. 返回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));
}