Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In XAML I want to use StringFormat to display a numerical value without any rounding happening. Is it possible?

So in my XAML I have this:

<TextBlock Text="{Binding MyDecimalProperty, StringFormat={}{0:#.###}}"/>

When the value of MyDecimalProperty is for example 5.35570256 then the TextBlock value shown is 5.356

Is there a way to have the TextBlock show 5.355 instead (i.e. to truncate the number instead rounding it) using StringFormat?

I know I can use a Value Converter but I wanted to know if I can use StringFormat or anything else defined in the XAML to achieve the same.

Update: People keep wondering why I don't want to use a converter. Please read above in bold. Its not that I don't want to; I just wanted to know if I can do the same with StringFormat or any other XAML construct.

Thank you.

like image 690
tolism7 Avatar asked Aug 04 '15 16:08

tolism7


3 Answers

I do not think you can do this simply with using StringFormat. Is there a reason why you do not want to use a converter? (see below).

Converter:

public class TruncateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            double truncated;
            if (Double.TryParse(value, out truncated))
            {
                return ((double)((int)(truncated * 1000.0))) / 1000.0;
            }
        }
        return string.Empty;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

Usage:

<TextBlock Text="{Binding MyDecimalProperty, Converter={StaticResource TruncateConverter}}"/>
like image 103
d.moncada Avatar answered Oct 13 '22 01:10

d.moncada


If you do not want to use a converter (I am not sure why, but you will have your reasons) you can consider changing the returned type of your binding source and then implementing IFormattable interface.

Take a look to this sample. First of all your MyDecimalProperty should not return a decimal anymore. You should change it in order to return a TruncatedDecimal. Here its code:

public class TruncatedDecimal : IFormattable
{
    private decimal value;

    public TruncatedDecimal(decimal doubleValue)
    {
        value = doubleValue;
    }

    public decimal Value
    {
        get
        {
            return value;
        }
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        int decimalDigits = Int32.Parse(format.Substring(1));
        decimal mult = (decimal)Math.Pow(10, decimalDigits);
        decimal trucatedValue = Math.Truncate(value * mult) / mult;

        return trucatedValue.ToString(format, formatProvider);
    }
}

Now in your XAML your can use the format string that you need:

<TextBlock Text="{Binding StringFormat={}N5}" Margin="5" FontSize="20" />

So, for example, if the DataContext is set in this way:

DataContext = new TruncatedDecimal(new Decimal(.4997888869));

You will see 0.49978. I hope this solution will be suitable for your needs and can help you.

like image 32
Il Vic Avatar answered Oct 13 '22 00:10

Il Vic


if I can use StringFormat or anything else defined in the XAML to achieve the same

StringFormat is specific to the Binding Markup Extension (actually the binding base BindingBase.StringFormat Property (System.Windows.Data)) and ultimately uses the .Net string formatting such as ToString("G3") (see Standard Numeric Format Strings) which rounds and doesn't truncate; so it is not possible to override in Xaml such features.


Create another property on the viewmodel which is an associated string type which simply parrot's the value wanted, but truncated. Then bind as such.

ViewModel

public decimal TargetDecimal
{
    get { return _TargetDecimal; }
    set { _TargetDecimal = value; 
        OnPropertyChanged("TargetDecimal"); 
        OnPropertyChanged("TargetValueTruncated"); }
}

// No error checking done for example
public string TargetValueTruncated
{
  get { return Regex.Match(_TargetDecimal.ToString(), @"\d+\.\d\d\d").Value; }
}

Xaml

<TextBlock Text="{Binding TargetDecimal, StringFormat=Original:   {0}}"/>
<TextBlock Text="{Binding TargetDecimal, StringFormat=Modified:   {0:#.###}}"/>
<TextBlock Text="{Binding TargetValueTruncated, StringFormat=Truncated: {0}}"/> 

Result

enter image description here

like image 35
ΩmegaMan Avatar answered Oct 13 '22 01:10

ΩmegaMan