Search code examples
c#buttonxamarincustom-renderer

Xamarin Forms - Load image in a Button


I looked extensively online but I couldn't find anything really specific to help me out in this trouble I am having.

I am trying to make a custom renderer for a Button component, in Xamarin forms. Why am I not using the XLabs ImageButton component? Because it's not compatible with Android 4.0.3, which is my current Android target version.

I also tried writing on my own some code that is that much worthless that I am quite shy to post, unless you really require me to :)

I am in need of this code because, without it, images just fail to load in buttons while trying to use them in any button like this:

<Button Image="someImage.png"/>

I tried following a tutorial, here:

http://blog.falafel.com/learning-xamarin-custom-renderers-in-xamarin-forms/

But I failed adapting it to my needs.


Solution

  • The proper way to do this is described in Chapter 13 of Charles Petzold's excellent book on Xamarin Forms: https://developer.xamarin.com/guides/xamarin-forms/creating-mobile-apps-xamarin-forms/

    My approach to this problem is (different than the book) to use a converter for the image file path. The Button.Image property is a FileImageSource object and it wants a file path. Unfortunately you cannot use embedded resources or a content file in the PCL. You must add an individual image file in each of the iOS, Android and UWP projects. The way I do this is to add the image to the PCL and use linking (option on the add existing file dialog).

    So here is my converter approach to the above issue

    <Button Image="{Binding Converter={StaticResource FileImageSourceConverter}, ConverterParameter=someImage.png}" />
    

    The static resource...

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:FileImageSourceConverter x:Key="FileImageSourceConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>
    

    The converter...

    public class FileImageSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string filename = parameter as string;
            switch(Device.RuntimePlatform)
            {
                case Device.iOS:
                case Device.Android:
                default:
                    return filename;
                case Device.Windows:
                    return Path.Combine("Images", filename);
            }
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The advantages of this approach is that (1) your XAML is not cluttered up with OnPlatform elements; (2) you don't need to put your images in the root directory of the UWP project; (3) much simpler than using a custom render to solve the same problem as some have suggested.