Search code examples
imagexamlxamarincaching

Is it possible to set Image source both from file and uri in xamarin forms?


I'm trying to build the xamarin image upload application. I want to show the local image before uploading it to the server, After that, I want to show image from server url. If I use Image source, it works well both local and server. But the server image cache problem occurs.

<Image Grid.Row="0"
    Source="{Binding Url}"
    Aspect="AspectFill"
    HeightRequest="60"
    BackgroundColor="black"
    WidthRequest="60"/>

So that, to disable caching, I'm using UriImageSource, it works on server url but it doesn't show the local image.

<Image Grid.Row="0"
    Aspect="AspectFill"
    HeightRequest="60"
    BackgroundColor="black"
    WidthRequest="60">
    <Image.Source>
        <UriImageSource Uri="{Binding Url}"
                        CachingEnabled="False"/>
        <!--FileImageSource File="{Binding Url}"/-->
    </Image.Source>
</Image>

Is it possible to use both file and uri image source in this Image? Thank you for your help.


Solution

  • Option 1:- Using binding Url

    Create converter (ImageConverter). Following ImageConverter has dummy code for testing. It uses static field (Please don't use static). You can bind Url property and based on the Url you can find whether image source is remote url or local image. And return UriImageSource or direct string (local image). In ViewModel initial value for Uri property will be local image and once remote image received set Uri to remote image and raise property changed event.

    //ImageConverter.cs
     public class ImageConverter : IValueConverter
        {
            public static int count = 1;
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                count++;
                var imageUri = System.Convert.ToString(value);
                if (imageUri.Contains("http") && (count % 2 == 0))
                {
                    UriImageSource uriImageSource = new UriImageSource();
                    uriImageSource.Uri = new Uri(imageUri);
                    uriImageSource.CachingEnabled = false;
                    return uriImageSource;
                }
                else
                {
                    return imageUri;//Local image
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    
    //Xaml header
    
    xmlns:local="clr-namespace:Monkeys.Converter"
    
    <ContentPage.Resources>
         <ResourceDictionary>
            <local:ImageConverter x:Key="imgConv" />
         </ResourceDictionary>
    </ContentPage.Resources>
    
    //Xaml content
    <Image Grid.Row="0"
             Source="{Binding  Url, Converter={StaticResource imgConv}}"
             Aspect="AspectFill" HeightRequest="60"
             BackgroundColor="black" WidthRequest="60"
             HorizontalOptions="CenterAndExpand">
    </Image>
    

    Option 2:- Using ConverterParameter

    As per my investigation xamarin.forms doesn't support ConverterParameter binding. So, there is a work around. Create a new bool property in your Model/ViewModel IsRemoteUri. And initial IsRemoteUri will be false once remote image fetched then change IsRemoteUri to true. Bind IsRemoteUri to ConverterParameter.

    And converter will be as below code.

     public class ImageConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                var imageUri = System.Convert.ToString(value);
                var isRemoteUri = (bool)parameter;
                if (isRemoteUri)
                {
                    var uriImageSource = new UriImageSource();
                    uriImageSource.Uri = new Uri(imageUri);
                    uriImageSource.CachingEnabled = false;
                    return uriImageSource;
                }
                else
                {
                    return imageUri;//Local image
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    

    I have used this code for testing