Tyler Livingston
Tyler Livingston

Reputation: 13

.NET Maui XAML Data Binding Failures on Int32 & Doubles

I have a .NET MAUI app using databinding and trying to format values as currency in an Entry field. The property is a double and the binding does work however I get XAML Data Binding Failures. Normal string fields work fine, only when using Double and Int32 do I get these failures. Clearly a double cannot store characters like a dollar sign, comma, or period so the error in general makes sense, but I cannot figure out how to have onscreen formatting but only pass the value without formatting.

public class LeaseAgreement : Base
{
    public string Description { get; set; }
    public DateTime DateLeaseStarted { get; set; }
    public int TotalMonths { get; set; }
    public int AnnualMiles { get; set; }
    public **double ExcessPerMileAmount** { get; set; }
<Label Grid.Row="3" Grid.Column="0" Text="Excess Milage Charge" Style="{StaticResource FormLabel}" />
<Entry Grid.Row="3" Grid.Column="1" Text="{Binding **ExcessPerMileAmount**, StringFormat='{0:C2}'}" Style="{StaticResource FormEntry}" Keyboard="Numeric" />

I've tried databinding with StringFormat (as seen above). I have also tried Behaviors on the Entry field.

The numeric value is captured and the application fully works in Windows, iOS, and Android. However it throws a ton of XAML Data Binding Failures and is messy, especially if using generic exception monitoring.

Any suggestions are greatly appreciated!

Upvotes: 1

Views: 545

Answers (2)

Abhishek khatri
Abhishek khatri

Reputation: 13

To format a numeric value as currency in a .NET MAUI Entry field while avoiding XAML data binding failures, you need to ensure that the formatting is correctly handled without causing binding issues. Since Entry expects the Text property to be a string, but the underlying property is a double, direct binding with formatting can lead to issues.

You can use a ValueConverter to handle the conversion between the double value and the formatted string for display. Additionally, you should manage the reverse conversion from the formatted string back to the double value.

using System;
using System.Globalization;
using Microsoft.Maui.Controls;

public class DoubleToCurrencyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is double doubleValue)
        {
            return doubleValue.ToString("C2", culture);
        }
        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is string stringValue)
        {
            if (double.TryParse(stringValue, NumberStyles.Currency, culture, out double result))
            {
                return result;
            }
        }
        return value;
    }
}

Update the ViewModel or Data Model (if necessary): Ensure that the ExcessPerMileAmount property in your LeaseAgreement class is defined correctly and that the class implements INotifyPropertyChanged if you want to observe property changes.

ValueConverter: The DoubleToCurrencyConverter handles the conversion from double to a formatted currency string for display and from a formatted currency string back to double for data binding.

Binding in XAML: The Entry field binds to the ExcessPerMileAmount property using the converter, ensuring that the displayed text is formatted as currency but the underlying value remains a double.

ViewModel or Data Model: The ExcessPerMileAmount property raises PropertyChanged notifications, allowing the UI to update correctly when the value changes.

Upvotes: -1

FreakyAli
FreakyAli

Reputation: 16547

Create a converter that can convert your currency type to a decimal value something similar to this:

public class CurrencyConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Decimal.Parse(value.ToString()).ToString("C");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string valueFromString = Regex.Replace(value.ToString(), @"\D", "");

            if (valueFromString.Length <= 0)
                return 0m;

            long valueLong;
            if (!long.TryParse(valueFromString, out valueLong))
                return 0m;

            if (valueLong <= 0)
                return 0m;

            return valueLong / 100m;
        }
    }

Define the same in your resources an example of this is below:

  <ContentPage.Resources>
    <ResourceDictionary>
      <util:CurrencyConverter x:Key="currencyConverter" />
    </ResourceDictionary>
  </ContentPage.Resources>

Use that in your text property

Text="{Binding SomeProperty, Converter={StaticResource currencyConverter}}"

And the property that you need to bind would be something like this:

    public decimal SomeProperty { get; set; }

If needed you can make this an observable property

This is based on the example I used back in the day for Xamarin forms which can be found here https://gist.github.com/alfeugds/786260ab70a49565070338052ceaee3e

Upvotes: 0

Related Questions