如何实现'Xamarin.Forms Two bindable properties inside a DataTemplateView'?

How to implement 'Xamarin.Forms Two bindable properties inside a DataTemplateView'?

我正在研究这种代码

我的图片资源class

[ContentProperty(nameof(Source))]
class ImageResourceExtension : IMarkupExtension
{
  public string Source { get; set; }
  public object ProvideValue(IServiceProvider serviceProvider)
  {
    var newImageSource = ImageSource.FromResource(Source, typeof(ImageResourceExtension).GetTypeInfo().Assembly);
    return newImageSource;
  }
}

我的列表模型class

class ListModel
{
   public string IconSource { get; set; }
   public string IconPath { get; set; }
}

我的 MyViewModel class

class MyViewModel : INotifyPropertyChanged
{
   public List<Models.ListModel> MyListModel { get; }
   public Command MyListCommand { get; }
   public MyViewModel()
   {
      MyListModel = new List<Models.ListModel>()
      {
         new Models.ListModel(){ IconSource="https://example.com/image1",IconPath="MyImage1.jpg"},
         new Models.ListModel(){ IconSource="https://example.com/image2",IconPath="MyImage2.jpg"}
      };
      MyListCommand = new Command(OnListClicked);
   }

   private async void OnListClicked(object value)
   {
      string valueString = value as string;
      await Launcher.OpenAsync(valueString);
   }
 }

我的观点class

<?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:images="clr-namespace:MyProject.Images"
    xmlns:models="clr-namespace:MyProject.Models"
    xmlns:viewModels="clr-namespace:MyProject.ViewModels"

...

   <ContentPage.BindingContext>
      <viewModels:MyViewModel/>
   </ContentPage.BindingContext>

   <ContentPage.Content>
     <StackLayout BindableLayout.ItemsSource="{Binding MyListModel}">
       <BindableLayout.ItemTemplate>
         <DataTemplate> <!-- line{setup path} -->
           <Image Source="{images:ImageResource Source={Binding Source={RelativeSource AncestorType={x:Type viewModels:MyListModel}}, Path=ImageSource}}">
             <Image.GestureRecognizers>
               <TapGestureRecognizer 
                 NumberOfTapsRequired="1" 
                 Command="{Binding Source={RelativeSource AncestorType={x:Type viewModels:MyListModel}}, Path=MyListCommand}" 
                 CommandParameter="{Binding ImagePath}"/>
             </Image.GestureRecognizers>
           </Image>
         </DataTemplate>
       </BindableLayout.ItemTemplate>
     </StackLayout>
   </ContentPage.Content>

我的问题是如何在此line: {setup path}为我的图像源设置动态或可绑定属性?

如果您能解决这个问题,我将不胜感激。 谢谢。

已编辑: 我忘记添加我的图像 Embedded resource 在我的共享代码中。

您可以使用Value Converters来实现这个功能。

假设您的图像放置在您的 xamarin 表单项目的文件夹 Images 中(例如 MyFormDemo)。

1.create EmbeddedToImageSourceConverter.cs

public class EmbeddedToImageSourceConverter: 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();
    }
}

2.InMyViewModel.cs的构造函数,初始化IconPath如下(添加MyFormDemo.Images.):

       public MyViewModel()
    {
        MyListModel = new List<ListModel>()
  {
     new ListModel(){ IconSource="https://example.com/image1",IconPath="MyFormDemo.Images.cherry.png"},
     new ListModel(){ IconSource="https://example.com/image2",IconPath="MyFormDemo.Images.love.png"}
  };
        MyListCommand = new Command(OnListClicked);
    }

3.Implement 接口 INotifyPropertyChanged 用于 class ListModel:

  public class ListModel: INotifyPropertyChanged
{
    public string IconSource { get; set; }
    //public string IconPath { get; set; }

    string _iconPath;
    public string IconPath
    {
        set { SetProperty(ref _iconPath, value); }

        get { return _iconPath; }
    }


    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

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

    public event PropertyChangedEventHandler PropertyChanged;
}

4.in xaml 您的页面:

<ContentPage.Resources>
    <MyFormDemo:EmbeddedToImageSourceConverter x:Key="converter">
    </MyFormDemo:EmbeddedToImageSourceConverter>
</ContentPage.Resources>

<ContentPage.BindingContext>
    <viewmodel:MyViewModel></viewmodel:MyViewModel>
</ContentPage.BindingContext>

<ContentPage.Content>
    <StackLayout BindableLayout.ItemsSource="{Binding MyListModel}">
        <BindableLayout.ItemTemplate>
            <DataTemplate>

                <!-- line{setup path} -->
                <Image Source="{Binding IconPath, Converter={StaticResource converter}}"  WidthRequest="60" HeightRequest=" 60" BackgroundColor="Gray">

                </Image>


            </DataTemplate>
        </BindableLayout.ItemTemplate>
    </StackLayout>
</ContentPage.Content>