Xaml - 如何从 ViewModel 使用 ImageSource

3

我有一个ObservableCollection<Item>,其中的Item既包含文件路径,也包含从磁盘中获取的某个图像的ImageSource

public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<MediaListItem>();

public class Item
{
    public string Image { get; set; } // Full path to the image
    public ImageSource ImageSource { get; set; }
}

然而,我无法通过XAML访问这两个属性并显示图像。

<ListView ItemsSource="{Binding MediaList}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout Padding="10">
                    <Image Source="{Binding ImageSource}" VerticalOptions="Fill"></Image>
                </StackLayout>
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

现在我很困惑,因为我可以通过标签在XAML中输出字符串Image,但是无法显示路径中的图片。


尝试绑定到图像路径字符串。这些路径是URL、完整文件路径、部分文件路径等吗? - Jason
至少在代码中,你没有名为MediaList的属性。 - Eldho
2个回答

3
您可以像这样使用 ImageSource.FromFile()ImageSource.FromUri() 来加载图片。
在Xaml中,可以这样写:
<Image  Source="{Binding  ImageSource}"  Aspect="AspectFit"  ></Image>

在代码中
public ObservableCollection<Item> MediaList { get; set; } = new ObservableCollection<Item>()
        {
            new Item
            {
                ImageSource = ImageSource.FromFile("xamarin.png")
            },
            new Item
            {
                ImageSource = ImageSource.FromUri(new Uri("https://istack.dev59.com/4mMod.webp"))
            }
        };
结果

enter image description here

更新

根据Microsoft-Local Images

图像文件可以添加到每个应用程序项目中,并从Xamarin.Forms共享代码中引用...

要在所有应用程序中使用单个图像,必须在每个平台上使用相同的文件名,并且它应该是有效的Android资源名称(即只允许小写字母,数字,下划线和句点)。

有关更多信息,请查看此处的答案

现在,如果您想显示图像而不将其添加到每个平台,则应使用转换器 例如:
  1. Create a new folder called ImagesFolder in shared code then add the image to it

    enter image description here

  2. In Code, create a new class called ByteArrayToImageSourceConverter like this

    public class ByteArrayToImageSourceConverter : IValueConverter 
    {
      public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      {   
        byte[] bytes;
        var assembly = GetType().GetTypeInfo().Assembly; // using System.Reflection;
    
        var stream = assembly.GetManifestResourceStream((string)value); // value = "App1.ImagesFolder.ninja.png"
        using (var ms = new MemoryStream()) // using System.IO; 
        {
            stream.CopyToAsync(ms);
            bytes = ms.ToArray();
        }
        return ImageSource.FromStream(() => new MemoryStream(bytes));
      }
      public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      {
        return null;
      }
    }
    

    View Model

    public ObservableCollection<Item> MediaList { get; set; } = new ObservableCollection<Item>()
    {
        new Item
        {
           Image  = "App1.ImagesFolder.ninja.png"
        }
    };
    
  3. In Xaml

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:local="clr-namespace:App1"
         x:Class="App1.MainPage">
    
      <ContentPage.Resources>
        <ResourceDictionary>
           <local:ByteArrayToImageSourceConverter  x:Key="ByteArrayToImageSourceConverter" />
       </ResourceDictionary>
     </ContentPage.Resources>
    
     <ListView ItemsSource="{Binding MediaList}" >
        <ListView.ItemTemplate>
          <DataTemplate>
            <ViewCell>
               <Image Source="{Binding Image, Converter={StaticResource ByteArrayToImageSourceConverter}}" />
            </ViewCell>
          </DataTemplate>
       </ListView.ItemTemplate>
     </ListView>
    
    </ContentPage>
    

相关链接

ByteArrayToImageSourceConverter - 将字节数组转换为图像源的转换器。

共享资源 - 介绍如何在XAML中使用共享资源。

如何在Xamarin中加载二进制图像?


如果图像在磁盘上的某个随机位置(例如桌面)而不是项目的子文件夹中,那么它可能无法正常工作,这是我的猜测。 - Bowser
@Bowser 我已经修改了我的回答。 - Anas Alweish

1

ImageSource 类型更改为 String

public class Item
{
    public string ImageSource { get; set; }
}

使用
List<Item> items = new List<Item>();
items.Add(new Item() { ImageSource = "*THE URL OF IMAGE*" });
ListView.ItemsSource = items;

正如您在上面看到的,我已经有一个字符串(文件路径),但是当使用“Binding Image”时,它不起作用,原因不明。换句话说,无论我是否将其更改为字符串,结果都是一样的(因为我已经尝试过了)。 - Bowser
你尝试过这段代码吗?List<Item> items = new List<Item>(); items.Add(new Item() { ImageSource = "*图片的URL地址*" }); ListView.ItemsSource = items; - Ahmed Walid
您可以通过以 @"File://" 开头的路径来使用磁盘上的图像。 - Ahmed Walid
我同意Ahmed的答案。在我的vmodel中,我有一个图像路径字符串属性如下,绑定到XAML中的图像:public string Text { get { return this.text; }set { this.text = value; this.OnPropertyChanged(nameof(Text)); }} - CloudArch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接