Формат как валюта без конечных нулей в wpf xaml - PullRequest
0 голосов
/ 14 декабря 2018

Предполагая, что у нас есть свойство 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 голосов
/ 14 декабря 2018

Я думаю, вам здесь нужно использовать конвертер из-за необходимости удалять конечные нули.Это, вероятно, требует немного больше работы, но:

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}}"/>
0 голосов
/ 16 декабря 2018

Во-первых, я хотел бы поблагодарить @Andy за его ответ , который побудил меня использовать IValueConverter.

Я публикую свое решение, которое предлагает следующие преимущества:

  1. Использование спецификатора формата C # "C"

    a.Учитывайте отрицательные значения (например, -1 --> ($1))

    b.Обслуживает различные текущие локали / культуры

  2. Привязка к нескольким типам данных (decimal, double, int и т. Д.).

  3. Возврат DependencyProperty.UnsetValue, когда ConvertBack не может получить значение .

Все вышеперечисленное следует, как StringFormat=c будет вести себя в wpf (например, вa 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;
}

Подробнее о ToCurrency здесь

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));
}
0 голосов
/ 14 декабря 2018

Возможно, вы знали бы, что «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)
...