3

As you guys know, there is no built-in type converter class to convert a string to ImageSource object.

That brough me a challenge when I want to have my models have a string property representing ResouceID for an embeded image and, then, XAML's Image.Source attribute bound to that property by data binding.

The easiest solution is adding another property of ImageSource type in the model which is only getting an image source object generated based on the string ResourceID peroperty and then, binding it to Image.Source.

It works well but the problem is I had to add Xamarin.Forms dependency to the project defining the model which was .NET Stardard class library.

I have split view and model/viewmodel by project so that the model can be reused at other applications. so, the model was designed to have only basic types like int, string, and so on. The easiest solution have made the model class dependent on Xamarin.Forms and I worry if it may bring about some issues later when I use for other frameworks.

In order to make a solution, I tried declaring a markup extension class with binding capability in the shared project by referring to MS documents but not working.

The extension class code is as below.


// This class is added to the shared project, where a page class exsists.
public class BindableImageSourceExtension : BindableObject, IMarkupExtension
{
    // This is a unique property of BindableImageSource element
    public string ResourceID
    {
        get { return (string)GetValue(ResouceIDProperty); }
        set { SetValue(ResouceIDProperty, value); }
    }

    public object ProvideValue(IServiceProvider serviceProvider)
    {
        if(ResourceID == null) return null;

        // Images are embeded to a project named BusinessSession that holds Data class.
        return ImageSource.FromResource(ResourceID, typeof(BusinessSession).GetTypeInfo().Assembly); 
    }

    public static readonly BindableProperty ResouceIDProperty =
            BindableProperty.Create("ResourceID", typeof(string),
                                    typeof(BindableImageSourceExtension),
                                    default(string));
}

Anybody can help this out?

Big Square
  • 35
  • 4

1 Answers1

2

There is no need to create a bindableproperty, the solution is listed in the document:

Because there is no built-in type converter from string to ResourceImageSource, these types of images cannot be natively loaded by XAML. Instead, a simple custom XAML markup extension can be written to load images using a Resource ID specified in XAML:

[ContentProperty (nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
 public string Source { get; set; }

 public object ProvideValue (IServiceProvider serviceProvider)
 {
   if (Source == null)
   {
     return null;
   }

   // Do your translation lookup here, using whatever method you require
   var imageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);

   return imageSource;
 }
}

And in Xaml:

 <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
   <!-- use a custom Markup Extension -->
   <Image Source="{local:ImageResource WorkingWithImages.beach.jpg}" />
 </StackLayout>

You can also create your own ValueConverter:

public class stringToImageSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ImageSource.FromResource(value as string, typeof(MainPage).GetTypeInfo().Assembly);
    }

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

And in Xaml:

<Image Source="{Binding Path, Converter={StaticResource stringToImage}}" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" />

I uploaded a sample project here.

Jack Hua
  • 14,231
  • 1
  • 5
  • 19
  • Thanks a lot, Jack. the second one is exactly what I want. Actually, I tried the first one but didn't work in terms of data binding. the second one is perfect. – Big Square Jun 23 '20 at 11:33
  • @BigSquare Can you please accept the answer (click the ☑️ in the upper left corner of this answer ) so that we can help more people with same problem:)? – Jack Hua Jun 24 '20 at 01:16
  • How to bind a converter with extension? I have am trying this with label in xamarin forms but its not working. I have done something like this: but it gives compile time error that property type Converter was not found in type ETranslateExtension. @JackHua – Divyesh_08 Feb 12 '21 at 06:25