简体   繁体   中英

EmbeddedImage in Xamarin Forms: how to bind it in XAML

I am trying to follow the Xamarin documentation about Embedded Images: https://developer.xamarin.com/guides/xamarin-forms/working-with/images/#Embedded_Images

This is the code snippet that I use in my portable application:

var embeddedImage = new Image { Aspect = Aspect.AspectFit };
embeddedImage.Source = ImageSource.FromResource("<MyNamespace>.<MyFolder>.imageFileName.jpg");

listItem.EmbeddedImage = embeddedImage;

Now I am trying to bind it in XAML, as part of a ListView ( note: the <Image Source="{Binding EmbeddedImage}" /> part is probably wrong) :

<ListView  x:Name="listView">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <StackLayout BackgroundColor="#eee"
        Orientation="Vertical">
          <StackLayout Orientation="Horizontal">
            <Image Source="{Binding EmbeddedImage}" /> // This is most likely wrong since it doesn't work       
          </StackLayout>
        </StackLayout>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

I've tested this with <Image Source="{Binding ImageUrl}" /> and it works, so the rest of the code seems to be working as it should.


Edit:

Someone suggested this post as a solution:

How to load an image to a ImageCell on Xamarin.Forms?

But the accepted answer there was:

The images go into your "native" projects

...but actually the Xamarin documentation says that it can be done inside the portable project (so you wouldn't need to copy the same images/icons through all the "native" projects).

I know that putting them in every subproject would probably work, but that's not the point of my question.

You can access the resource directly in xaml by using pack://application uri.

<ListView  x:Name="listView">
  <ListView.ItemTemplate>
    <DataTemplate>
      <ViewCell>
        <StackLayout BackgroundColor="#eee"
        Orientation="Vertical">
          <StackLayout Orientation="Horizontal">
            <Image Source="pack://application:,,,/{AssemblyName};component/Images/MyImage.png" />     
          </StackLayout>
        </StackLayout>
      </ViewCell>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

I've combed my hair out over this, and the problem is that Microsoft doesn't tell you the whole story in the Images docs. You have to go over to the Files docs to understand why it won't work.

Yes, you can use embedded resources in the shared project directory, but apparently under only one of two conditions:

  1. You have to use a Markup Extension and then directly specify the resource path in Xaml, a la: <Image Source="{local:ImageResource ProjectName.Images.flower.jpg"/>
  2. You write compiler directives in the code-behind that customize the beginning of the ResourceID per-platform.

Option 1 requires hard-coding the path, so you can't use a dynamically-assigned image, and Option 2 wrecks the whole point of trying to write cross-platform code.


WAY HUGE EDIT: May be solved

This post on the Xamarin forums made a huge difference for me: https://forums.xamarin.com/discussion/17953/helpful-shared-project-image-information

note: the first post basically gives you all the code you need, but a little bit down in the thread there's some advice about project configurations that may be necessary for it to work correctly.

It basically introduces some custom code that programmatically derives the resource ID during runtime, so it's cross-platform code that customizes itself to whatever platform is currently running it. Working beautifully for me! Here's the version of the suggested approach that I'm using:

using System.Linq;
using System.Reflection;
using System.Diagnostics;
using System;

namespace Helpers
{
    public class EmbeddedSourceror
    {
        public static Xamarin.Forms.ImageSource SourceFor(string pclFilePathInResourceFormat)
        {
            var resources = typeof(EmbeddedSourceror).GetTypeInfo().Assembly.GetManifestResourceNames();
            var resourceName = resources.Single(r => r.EndsWith(pclFilePathInResourceFormat, StringComparison.OrdinalIgnoreCase));
            Debug.WriteLine("EmbeddedSourceror: resourceName string is " + resourceName);

            return Xamarin.Forms.ImageSource.FromResource(resourceName);
        }
    }
}

This lets you write the Xaml code in a totally normal way, such as:

<Image
            x:Name         ="backingImage"
            Aspect         ="AspectFill" />

And in the code-behind all you have to do is:

    backingImage.Source = EmbeddedSourceror.SourceFor("flower.jpg");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM