Home > Software engineering >  How can I implement binding for an Imbedded Image Resource?
How can I implement binding for an Imbedded Image Resource?

Time:09-29

  1. Hi so I am trying to connect the ImageButton Source to a changeable String property in my MainPage. I´m not sure if its the right way to do it. However I am trying to find a way to bind both together using a Binding Expression.
namespace MyNameSpace
{
    public partial class MainPage : ContentPage, INotifyPropertyChanged
    {

        public new  event PropertyChangedEventHandler PropertyChanged;
        public String One => "MyNameSpace.Images.Blue.jpg";

        public MainPage()
        {

            InitializeComponent();

        }
        protected override void OnPropertyChanged ([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        } 
   }
}

This is the MarkUpExtension I created to give a String as a Resource as I'm using an Embedded Image Resource.

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace MyNameSpace
{
    [ContentProperty("ResourceId")]
    public class EmbeddedImage : IMarkupExtension
    {
        public string ResourceId { get; set;}
        public object ProvideValue(IServiceProvider serviceProvider)
        {
            if (String.IsNullOrWhiteSpace(ResourceId))
                return null;
            return ImageSource.FromResource(ResourceId);
        }
    }
}

And this is how I was trying to bind the string together in xaml...

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MyNameSpace"
             x:Class="MyNameSpace.MainPage"
             x:Name = "Main">

    <StackLayout
        BindingContext="{x:Reference Name=Main }">
        
       <Image
           
           Source="{local:EmbeddedImage ResourceId = {Binding One}}">
          
       </Image>    
       
    </StackLayout>

</ContentPage>

Obviously it doesn't work... I get the error: MainPage.xaml(13, 12): [XFC0009] No property, BindableProperty, or event found for "ResourceId", or mismatching type between value and property.

Maybe this isn't the way to do it. I would really appreciete someone "teaching" me even with a different approach. Thank you very much.

CodePudding user response:

You have a string that can be changed, and that string represents an embedded resource (image)

My recommendation is to use Value Converters

First thing, you will have to modify the string property to notify the UI in case the value changes

private string _one;
public string One
{
get=>_one; 
set{_one=value; NotifyPropertyChanged();}
}

Then you have to create a new class for the converter, here will go your code to transform a string into a ImageSource

public class converter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string ResourceId=value.ToString(); 
            if (String.IsNullOrWhiteSpace(ResourceId))
                return null;
            return ImageSource.FromResource(ResourceId);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Then, just as any other converter, add it to your application resources in App.xaml. This will vary depending on your name class and namespace

        <converters:converter x:Key="myConverter"/>

And finally, the code for the image

<Image Source="{Binding One, Converter={StaticResource myConverter}}"/>

Also, if your application keeps growing, consider separating the ViewModel to another class

Happy coding!

CodePudding user response:

Don't need to write a markup extension.

  1. Create an ImageSource property and bind to that in the xaml.
  2. Set the property using ImageSource.FromStream method (and pass the embedded image stream).

Check out the example below.

Code Behind

using System;
using System.IO;
using System.Reflection;

using Xamarin.Forms;

namespace App5
{
    public partial class MainPage
    {
        public MainPage()
        {
            InitializeComponent();
            SetImage();
        }

        private int Num = 1;
        private static readonly Assembly Assembly = typeof(MainPage).Assembly;

        private ImageSource _Source;
        public ImageSource Source
        {
            get => _Source;
            set
            {
                _Source = value;
                OnPropertyChanged();
            }
        }

        private void SetImage()
        {
            Source = ImageSource.FromStream(() => GetResourceStream($"{Num}.png"));
        }

        private void bChange_OnClicked(object sender, EventArgs e)
        {
            Num = Num == 1 ? 2 : 1;
            SetImage();
        }

        private static Stream GetResourceStream(string filename)
            => Assembly.GetManifestResourceStream($"App5.{filename}");
    }
}

XAML

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="App5.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Name="This">

    <StackLayout>
        <Button Text="Change" Clicked="bChange_OnClicked" />
        <Image x:Name="img" Source="{Binding Source,Source={x:Reference This}}" />
    </StackLayout>
</ContentPage>

In order to make the example work, you need to set the project default namespace to App5 and embed two images with filenames 1.png and 2.png in the root folder.

  • Related