Your most important Xamarin Converter: InverseBoolConverter

7/19/2022

I am currently re-writing my phone app for my bank budgeting application (Quid). One page is the list of Transactions. Transfers (transferring between "Envelopes") don't have a balance. Therefore I want a different <Label ...\> displayed for the Amount column of all Transfer transactions:

Obviously this needs to bind something to IsVisible.

My viewmodel already has an IsTransfer property on it:

class TransactionViewModel
{
    public bool IsTransfer { get; set; }
}

With this, I can bind the "N/A" label as such:

<Label 
   IsVisible="{Binding IsTransfer}" 
   Text="N/A" 
/>

However, now I need the Amount label to be hidden when this is displayed. It therefore needs to bind to the inverse of IsTransfer. Unfortunately we can't bind to !IsTransfer.

Hack #1: Add another property to the viewmodel

Since we can't bind to !IsTransfer, here's a quick hack: Add a IsNotTransaction property to my view model:

class TransactionViewModel
{
    public bool IsTransfer { get; set; }
    public bool IsNotTransaction { get { return !IsTransfer; } }
}

Now map my amount Label to it:

<Label 
    IsVisible="{Binding IsNotTransfer}" 
    Text="{Binding Amount, StringFormat='{0:c}'}" 
/>

Although this works, it's sloppy coding. The preferred is...

Option #2: Use an IValueConverter.

There's a more proper answer to this. Converters are rather easy to write. Create a class that inherits from IValueConvert and add it to your project. For mine, I needed to invert a bool to essentially get !IsTransfer. So I created this class:

namespace QuidXam.Infrastructure.Converters
{
  public class InverseBoolConverter : IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !((bool)value);
    }

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

Next, this needs to be added to a ResourceDictionary. This can be done in each page where you need it, but I prefer to place it in the App.xaml file. In there, add the namespace, and this entry into the ResourceDictionary:

xmlns:converter="clr-namespace:QuidXam.Infrastructure.Converters"
...
<Application.Resources>
    <ResourceDictionary>
        <converter:InverseBoolConverter x:Key="inverseBoolConverter" />
    </ResourceDictionary>
</Application.Resources>

Now I no longer need my IsNotTransfer property, and my Amount Label can be implemented as follows:

<Label 
   IsVisible="{Binding IsTransfer, Converter={StaticResource inverseBoolConverter}}"
   Text="{Binding Amount, StringFormat='{0:c}'}" 
/>

Of all the IValueConverter's you would create, this one is the most useful. As I mentioned, just about every Xamarin app you create will most likely need this.


Please register or login to add a comment.

Comments (displaying 1 - 1):
No comments yet! Be the first...


  • C#/.NET/Core
  • T-SQL
  • HTML/Javascript/jQuery
  • ASP.NET/MVC
  • .NET Core
  • ADO.NET/EF
  • WPF
  • Xamarin/MAUI
  • Windows 10
  • SQL Server 20xx
  • Android
  • XBox One
  • Skiing
  • Rock Climbing
  • White water kayaking
  • Road Biking