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.