2013-11-25 8 views
25

decimalの値にはかなり面倒な書式設定が必要です。一言で言えば、3番目の小数点が5の場合を除き、末尾に2桁の小数点以下を表示します。小数点以下3桁まで表示します。組み込み型のカスタム書式設定機能を拡張する

この書式設定もかなり柔軟である必要があります。具体的には、後続スペースは必ずしも望ましくなく、第3小数点が「5」のときは「1/2」が好ましい。

例:それ

  • 1.315せずにスペースまたは "01.13" と "01.13" は "01.315" または "01.31½"
  • として表示されるように

    • 1.13が表示されます

      私はこのロジックを無関係なUIの部分で一貫して使用する必要があります。私は一時的にWPF値コンバータとして、それを書かれているが、これは単なるデモンストレーション用です:私は今、私は私のUI層全体に使用することができ、より基本的なビルディングブロックにこれを抽出しようとしています

      public sealed class PriceConverter : IValueConverter 
      { 
          public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
          { 
           if (!(value is decimal)) 
           { 
            return DependencyProperty.UnsetValue; 
           } 
      
           var decimalValue = (decimal)value; 
           var formattedDecimalValue = decimalValue.ToString("#0.000", CultureInfo.InvariantCulture); 
           var lastFormattedChar = formattedDecimalValue[formattedDecimalValue.Length - 1]; 
      
           switch (lastFormattedChar) 
           { 
            case '0': 
             return formattedDecimalValue.Substring(0, formattedDecimalValue.Length - 1) + " "; 
            case '5': 
             return formattedDecimalValue.Substring(0, formattedDecimalValue.Length - 1) + "½"; 
            default: 
             return formattedDecimalValue; 
           } 
          } 
      
          public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
          { 
           throw new NotImplementedException(); 
          } 
      } 
      

      。それはだ場合のみ、小数点以下第3位を示しているフォーマット文字列がに示した「#0.005」のようなものにすることができている

      <TextBlock Text="{Binding Value, FormatString=WHATEVER}"/> 
      

      アイデア:私の最初の考えは、私はその後、Bindingから使用できるカスタム書式プロバイダました5、または小数点第3小数点を表現しようとする "#0.00F"。しかし、バインディングから特定のフォーマットプロバイダを使用する手段を見つけることができませんでしたが、これは私の大きな制限のようですが、何か不足しているのでしょうか?このタイプは、私が必要と余分な書式設定機能をカプセル化します

      public struct Price : IFormattable 
      

      :より多くの実験と調査の後

      は、私は私の唯一のオプションは、自分のタイプを定義することであるという結論に達しました。しかし、今私は別の問題を抱えています:私のToString実装では、自分自身を妨害することなく、decimal.ToString(string, IFormatProvider)の既存の書式設定機能をどのように活用できますか?これはかなりかわいそうだろうと思うし、 "G"(小数点以下2桁または3桁、末尾のスペースなし)と "S"( "G"と同じですが、必要に応じて末尾のスペースを使用して)私のPrice構造のためのフォーマット。

      このような種類のカスタム書式設定機能を、あまりにも面倒なく実行する方法があるかどうかは誰にでも分かりますか?

    +0

    うに文字列の作業をフォーマットするためのいくつかのユニークな接頭辞カスタムとデフォルトの書式を区別できますか?カスタムの場合は "&#0.00"、デフォルトの場合は "#0.00"のようになります(最初の文字が特殊な場合はカスタムを使用します)。) –

    +0

    @Alexei:書式設定コードを完全に所有したい場合にのみ機能しますが、組み込みの書式設定に委任してから自分のビットと部分を補足することをお勧めします。さもなければ、私は組み込み機能の非常に多くを再実装する必要があります。 –

    +0

    これを試してみてください。http://stackoverflow.com/questions/11438089/how-to-delegate-to-default-format-provider – amald

    答えて

    1

    詳細はhttp://msdn.microsoft.com/en-us/library/system.iformatprovider.aspxを参照してください。

    // "01.13 " or "01.13". Standard formatting applied: $123.45 
    // "01.315" or "01.31½". Standard formatting applied: $123.45 
    
    public class Test 
    { 
        void Main() 
        { 
         decimal number1 = 1.13M; 
         decimal number2 = 1.315M; 
    
         string output1 = String.Format(new CustomNumberFormat(), 
               "\"{0:G}\" or \"{0:S}\". Standard formatting applied: {1:C2}", 
               number1, 123.45); 
         Console.WriteLine(output1); 
    
         string output2 = String.Format(new CustomNumberFormat(), 
               "\"{0:G}\" or \"{0:S}\". Standard formatting applied: {1:C2}", 
               number2, 123.45); 
         Console.WriteLine(output2); 
        } 
    } 
    
    public class CustomNumberFormat : System.IFormatProvider, System.ICustomFormatter 
    { 
        public object GetFormat(Type formatType) 
        { 
         if (formatType == typeof(ICustomFormatter)) 
          return this; 
         else 
          return null; 
        } 
    
        public string Format(string fmt, object arg, System.IFormatProvider formatProvider) 
        { 
         // Provide default formatting if arg is not a decimal. 
         if (arg.GetType() != typeof(decimal)) 
          try 
          { 
           return HandleOtherFormats(fmt, arg); 
          } 
          catch (FormatException e) 
          { 
           throw new FormatException(String.Format("The format of '{0}' is invalid.", fmt), e); 
          } 
    
         // Provide default formatting for unsupported format strings. 
         string ufmt = fmt.ToUpper(System.Globalization.CultureInfo.InvariantCulture); 
         if (!(ufmt == "G" || ufmt == "S")) 
          try 
          { 
           return HandleOtherFormats(fmt, arg); 
          } 
          catch (FormatException e) 
          { 
           throw new FormatException(String.Format("The format of '{0}' is invalid.", fmt), e); 
          } 
    
         // Convert argument to a string. 
         string result = ((decimal)arg).ToString("0#.000"); 
    
         if (ufmt == "G") 
         { 
          var lastFormattedChar = result[result.Length - 1]; 
          switch (lastFormattedChar) 
          { 
           case '0': 
            result = result.Substring(0, result.Length - 1) + " "; 
            break; 
          } 
    
          return result; 
         } 
         else if (ufmt == "S") 
         { 
          var lastFormattedChar = result[result.Length - 1]; 
          switch (lastFormattedChar) 
          { 
           case '0': 
            result = result.Substring(0, result.Length - 1); 
            break; 
           case '5': 
            result = result.Substring(0, result.Length - 1) + "½"; 
            break; 
          } 
    
          return result; 
         } 
         else 
         { 
          return result; 
         } 
        } 
    
        private string HandleOtherFormats(string format, object arg) 
        { 
         if (arg is System.IFormattable) 
          return ((System.IFormattable)arg).ToString(format, System.Globalization.CultureInfo.CurrentCulture); 
         else if (arg != null) 
          return arg.ToString(); 
         else 
          return String.Empty; 
        } 
    } 
    
    +0

    ありがとうございます。/'' S ''はフォールバックプランでした。あなたが提案したものよりはるかに簡単な実装で(IFormattableはキーであり、バインディングからも確実に働いていましたが、あなたの提案はコンバーターなしではできませんでした)私が実際に望んだのは、標準フォーマットではなく、カスタムフォーマットをサポートすることでした。 ''#0.005 ''のような私の質問の先の例を見てください。組み込みの独自の書式設定を独自のもので補完しようとすると、むしろ委任したいと思うたくさんのものを再実装する必要があります。 –

    0

    あなたIValueConverter.Convert実装でparameter引数としてごフォーマットプロバイダーに渡してみてください。あなたのコンバータの内部で、

    <TextBlock Text="{Binding Value, Mode=OneWay, Converter={StaticResource PriceConverter}, ConverterParameter=#0.00F"/> 
    

    その後:

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
        string formatString = parameter as string; 
    
        if(formatString != null) 
        { 
         // Your code here 
        } 
        else 
        { 
         // Whatever you want to do here 
        } 
    
    } 
    
    関連する問題