Xamarin Forms Converters

I love Converters in Xamarin Forms. They give you a nice, easy way to display something through your XAML based on a value in your binding data. And they are so easy to set up.

All converters inherit from IValueConverter and must implement two methods: Convert and ConvertBack.

public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// do something to get a new value
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// and change it back if you want to
}
}
view raw MyConverter.cs hosted with ❤ by GitHub

Then, to use it, in your XAML, add your reference to the converter in either your App.xaml (if you expect to use it a lot) or directly on the page you wish to use it.

<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml&quot;
xmlns:converter="clr-namespace:MyApp.Converter;assembly=MyApp"
x:Class="MyApp.App">
<Application.Resources>
<ResourceDictionary>
<converter:ItemTappedEventArgsConverter x:Key="ItemTappedEventArgsConverter" />
<converter:FirstValidationErrorConverter x:Key="FirstValidationErrorConverter" />
<converter:BooleanNegationConverter x:Key="Inverter" />
</ResourceDictionary>
</Application.Resources>
</Application>
view raw App.xaml hosted with ❤ by GitHub

I think the easiest way to see this in action is to run through some of the converters I’ve used. Most of these are probably common to a lot of Xamarin developers, but I’m going to add them in any way.

Boolean Negation Converter

This lets you convert a true to false, and false to true (obviously!)

public class BooleanNegationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}

First Validation Error Converter

This is a converter I came across while learning Xamarin Forms, from a Microsoft example project. It allows you to display the first error set against a bound value that is a ValidatableObject. I’d recommend looking at the eShopOnContainers sample code if you’re interested in learning more about this.

public class FirstValidationErrorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ICollection<string> errors = value as ICollection<string>;
return errors != null && errors.Count > 0 ? errors.ElementAt(0) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Item Tapped Event Args Converter

This is another I came across when first learning Xamarin Forms and I still use it quite a bit.

public class ItemTappedEventArgsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var eventArgs = value as ItemTappedEventArgs;
if (eventArgs == null)
throw new ArgumentException("Expected TappedEventArgs as value", "value");
return eventArgs.Item;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

This allows you to capture an action against a control and bind it to a command. It needs to be used in conjunction with a Behavior, but it’s a very useful combo.

public class EventToCommandBehavior : BindableBehavior<Xamarin.Forms.View>
{
public static BindableProperty CommandProperty =
BindableProperty.CreateAttached(
"Command",
typeof(ICommand),
typeof(EventToCommandBehavior),
null,
BindingMode.OneWay);
public static BindableProperty CommandParameterProperty =
BindableProperty.CreateAttached(
"CommandParameter",
typeof(object),
typeof(EventToCommandBehavior),
null,
BindingMode.OneWay);
public static BindableProperty EventArgsConverterProperty =
BindableProperty.CreateAttached(
"EventArgsConverter",
typeof(IValueConverter),
typeof(EventToCommandBehavior),
null,
BindingMode.OneWay);
public static BindableProperty EventArgsConverterParameterProperty =
BindableProperty.CreateAttached(
"EventArgsConverterParameter",
typeof(object),
typeof(EventToCommandBehavior),
null,
BindingMode.OneWay);
protected Delegate _handler;
private static BindableProperty EventNameProperty =
BindableProperty.CreateAttached(
"EventName",
typeof(string),
typeof(EventToCommandBehavior),
null,
BindingMode.OneWay);
private EventInfo _eventInfo;
public string EventName
{
get { return (string)GetValue(EventNameProperty); }
set { SetValue(EventNameProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public IValueConverter EventArgsConverter
{
get { return (IValueConverter)GetValue(EventArgsConverterProperty); }
set { SetValue(EventArgsConverterProperty, value); }
}
public object EventArgsConverterParameter
{
get { return GetValue(EventArgsConverterParameterProperty); }
set { SetValue(EventArgsConverterParameterProperty, value); }
}
protected override void OnAttachedTo(Xamarin.Forms.View visualElement)
{
base.OnAttachedTo(visualElement);
var events = AssociatedObject.GetType().GetRuntimeEvents().ToArray();
if (events.Any())
{
this._eventInfo = events.FirstOrDefault(e => e.Name == EventName);
if (this._eventInfo == null)
throw new ArgumentException(String.Format("EventToCommand: Can't find any event named '{0}' on attached type", EventName));
AddEventHandler(this._eventInfo, this.AssociatedObject, this.OnFired);
}
}
protected override void OnDetachingFrom(Xamarin.Forms.View view)
{
if (this._handler != null)
{
this._eventInfo.RemoveEventHandler(this.AssociatedObject, this._handler);
}
base.OnDetachingFrom(view);
}
private void AddEventHandler(EventInfo eventInfo, object item, Action<object, EventArgs> action)
{
var eventParameters = eventInfo.EventHandlerType
.GetRuntimeMethods().First(m => m.Name == "Invoke")
.GetParameters()
.Select(p => Expression.Parameter(p.ParameterType))
.ToArray();
var actionInvoke = action.GetType()
.GetRuntimeMethods().First(m => m.Name == "Invoke");
this._handler = Expression.Lambda(
eventInfo.EventHandlerType,
Expression.Call(Expression.Constant(action), actionInvoke, eventParameters[0], eventParameters[1]),
eventParameters)
.Compile();
eventInfo.AddEventHandler(item, this._handler);
}
private void OnFired(object sender, EventArgs eventArgs)
{
if (this.Command == null)
{
return;
}
var parameter = this.CommandParameter;
if (eventArgs != null && eventArgs != EventArgs.Empty)
{
parameter = eventArgs;
if (this.EventArgsConverter != null)
{
parameter = this.EventArgsConverter.Convert(eventArgs, typeof(object), this.EventArgsConverterParameter, CultureInfo.CurrentUICulture);
}
}
if (this.Command.CanExecute(parameter))
{
this.Command.Execute(parameter);
}
}
}

For example, I can bind the tapping of a ListView item to my code in my View Model by doing:-

<ListView ItemsSource="{Binding ListData}" HasUnevenRows="True">
<ListView.Behaviors>
<behaviors:EventToCommandBehavior EventName="ItemTapped" Command="{Binding ListItemSelected}" EventArgsConverter="{StaticResource ItemTappedEventArgsConverter}" />
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!- your layout here–>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</List>

String Has Value Converter

This was one I used to show a message if one had been supplied when a busy indicator was being displayed.

public class StringHasValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return false;
return !string.IsNullOrEmpty(value.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
x:Class="MyApp.Styles.Indicator"
xmlns="http://xamarin.com/schemas/2014/forms&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"&gt;
<ControlTemplate x:Key="MainTemplate">
<Grid BindingContext="{TemplateBinding BindingContext}">
<ContentPresenter Grid.Row="0" />
<!– 'Busy' indicator –>
<StackLayout
Grid.Row="0"
BackgroundColor="{DynamicResource BackgroundIndicatorColor}"
HorizontalOptions="FillAndExpand"
IsVisible="{TemplateBinding BindingContext.IsBusy}"
VerticalOptions="FillAndExpand">
<StackLayout
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
<Frame
Margin="10"
Padding="10"
CornerRadius="40"
HeightRequest="100"
WidthRequest="200">
<StackLayout>
<ActivityIndicator
BackgroundColor="Transparent"
HeightRequest="48"
HorizontalOptions="Center"
IsRunning="{TemplateBinding BindingContext.IsBusy}"
IsVisible="{TemplateBinding BindingContext.IsBusy}"
VerticalOptions="Center"
WidthRequest="48"
Color="{DynamicResource IndicatorColor}" />
<Label
IsVisible="{TemplateBinding BindingContext.IsBusyText,
Converter={StaticResource StringHasValueConverter}}"
HorizontalOptions="Center"
HorizontalTextAlignment="Center"
Style="{DynamicResource TextPrimaryColor}"
Text="{TemplateBinding BindingContext.IsBusyText}" />
</StackLayout>
</Frame>
</StackLayout>
</StackLayout>
</Grid>
</ControlTemplate>
</ResourceDictionary>
view raw indicator.xaml hosted with ❤ by GitHub

Alternate Row Colour Converter

Set alternating colours on a Listview.

public class AlternateRowColourConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || parameter == null) return Color.LightGray;
var index = ((ListView)parameter).ItemsSource.Cast<object>().ToList().IndexOf(value);
if (index % 2 == 0)
{
return "#eaecef";
}
else
{
return "#d7d9dd";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid
Padding="5"
BackgroundColor="{Binding ., Converter={StaticResource AlternateRowColourConverter}, ConverterParameter={x:Reference ItemsToFit}}"
HorizontalOptions="FillAndExpand">
<!– your stuff here –>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
view raw ListView.xaml hosted with ❤ by GitHub

Direction Icon Converter

This was used to display a direction icon, utilising the Material Design Icons as per James Montemagno’s post, making it really easy to show an icon against each row.

public class DirectionIconConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var direction = value.ToString().ToLower();
switch (direction)
{
case "north":
return IconConstants.ArrowUpBoldCircle;
case "south":
return IconConstants.ArrowDownBoldCircle;
case "east":
return IconConstants.ArrowRightBoldCircle;
case "west":
return IconConstants.ArrowLeftBoldCircle;
default:
return IconConstants.HelpCircle;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
direction

Conclusion

Hopefully, this has shown just how useful and easy converters are to use, as well as some ideas on how you could use them in your apps.

Leave a comment