【问题标题】:How to change image source when a property changes through databinding in XAML from viewmodel in xamarin forms?当属性通过 XAML 中的数据绑定从 xamarin 表单中的视图模型更改时,如何更改图像源?
【发布时间】:2021-04-06 21:44:17
【问题描述】:

我正在努力为我的应用程序提供愿望清单功能,方法是通过 MVVM 在列表中的每个产品上点击愿望清单图标。一旦被点击,就会调用 API 来更新数据库(从愿望清单表中添加/删除)。根据 api 调用的结果,我将特定产品的相应属性更新为“真”或“假”。属性更新后,我想更改相应产品的图标图像源。我在愿望清单图标上使用触发器来区分非愿望清单和 wiahlist 产品,同时绑定列表本身。

我的代码如下,

型号

public class PublisherProducts
{
   public long ProductId { get; set; }
   public string ProductName { get; set; }
   public string ImageURL { get; set; }
   public decimal Price { get; set; }
   public bool IsWishlistProduct { get; set; }
}

视图模型

public class OnlineStoreViewModel : BaseViewModel
{
 private ObservableCollection<PublisherProducts> publisherProducts;
 public Command<long> WishlistTapCommand { get; }

 public OnlineStoreViewModel()
 {
    publisherProducts = new ObservableCollection<PublisherProducts>();
    WishlistTapCommand = new Command<long>(OnWishlistSelected);
 }

 public ObservableCollection<PublisherProducts> PublisherProducts
 {
   get { return publisherProducts; }
   set
   {
    publisherProducts = value;
    OnPropertyChanged();
   }
 }                  

 public async Task GetProducts(long selectedCategoryId)
 {
  try
    {
      ...
      PublisherProducts = new ObservableCollection<PublisherProducts>(apiresponse.ProductList);
      ...
    }
    catch (Exception ex) {  ... }
    finally {  ... }
 }

 async void OnWishlistSelected(long tappedProductId)
 {
   if (tappedProductId <= 0)
     return;
   else
     await UpdateWishlist(tappedProductId);
 }

 public async Task UpdateWishlist(long productId)
 {
   try
   {
    var wishlistResponse = // api call
    var item = PublisherProducts.Where(p => p.ProductId == productId).FirstOrDefault();
    item.IsWishlistProduct = !item.IsWishlistProduct;

    PublisherProducts = publisherProducts;  *Stuck here to toggle wishlist icon*

    await App.Current.MainPage.DisplayAlert("", wishlistResponse.Message, "Ok");
   }
   catch (Exception ex) {  ... }
   finally {  ... }
 }    
}

XAML

    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" ... >
     <ContentPage.Content>
      <ScrollView>
        <StackLayout Padding="15,0,15,10">
         <FlexLayout x:Name="flxLayout" BindableLayout.ItemsSource="{Binding PublisherProducts}" ...>
           <BindableLayout.ItemTemplate>
             <DataTemplate>
               <AbsoluteLayout Margin="6" WidthRequest="150">
                  <Frame Padding="0" WidthRequest="150" CornerRadius="10" HasShadow="True">
                     <StackLayout Orientation="Vertical" Padding="10" HorizontalOptions="FillAndExpand">
                       <Image Source="{Binding ImageURL}" WidthRequest="130" HeightRequest="130" HorizontalOptions="Center"/>
                       <Label Text="{Binding ProductName}" Style="{StaticResource ProductNameStyle}"></Label>
                       ...
                       <StackLayout ...>
                         ...                                                
                         <Frame x:Name="wlistFrame" Padding="0" WidthRequest="30" HeightRequest="30" CornerRadius="10" BorderColor="#02457A">
                           <StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
                              <Image x:Name="wlImage" WidthRequest="13" HeightRequest="12" HorizontalOptions="Center" VerticalOptions="Center" Source="ic_wishlist_open">
                                <Image.Triggers>
                                   <DataTrigger TargetType="Image" Binding="{Binding IsWishlistProduct}" Value="true">
                                      <Setter Property="Source" Value="ic_wishlist_close" />
                                   </DataTrigger>
                                </Image.Triggers>
                               </Image>
                            </StackLayout>
                            <Frame.GestureRecognizers>
                                <TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type local:OnlineStoreViewModel}}, Path=WishlistTapCommand}" CommandParameter="{Binding ProductId}" NumberOfTapsRequired="1" />                                                        
                            </Frame.GestureRecognizers>
                         </Frame>

                       </StackLayout>                                            
                     </StackLayout>
                  </Frame>                                    
               </AbsoluteLayout>
             </DataTemplate>
          </BindableLayout.ItemTemplate>
        </FlexLayout>
       </StackLayout>          
     </ScrollView>
    </ContentPage.Content>
  </ContentPage>

当 UpdateWishlist() 中的“IsWishlistProduct”属性值发生更改时,我被困在这个地方以更改愿望列表图标。

【问题讨论】:

  • 显示两个图标并根据需要切换它们的 IsVisible 属性可能会更简单
  • @Jason,你的意思是像 IsVisible = {Binding IsWishlistProduct}。我也试过了。当 VM 中“IsWishlistProduct”的值发生变化时,它不会反映在 View 中。
  • 如果您希望在模型更改时刷新 UI,您的模型必须实现 INotifyPropertyChanged
  • 模型还是视图模型? VM 已经通过 BaseViewModel 继承了它
  • 无论哪个类包含 IsWishlistProduct,如果这是您想要触发 UI 更改的属性

标签: xamarin.forms mvvm data-binding


【解决方案1】:

通过您的代码猜测,BaseViewModel 包含类似于以下的代码:

public class BaseViewModel : INotifyPropertyChanged
{
   ...
   public event PropertyChangedEventHandler PropertyChanged;
   ...

   public void OnPropertyChanged(string name)
   {
      this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
   }
   ...
}

你的视图模型应该是这样的:

...
public ObservableCollection<PublisherProducts> PublisherProducts
 {
   get { return publisherProducts; }
   set
   {
    publisherProducts = value;
    OnPropertyChanged(nameof(PublisherProducts));
   }
 }
...          

正如 Jason 所说,如果 ViewModel 中的数据发生变化,通过 NotifyPropertyChanged 通知给 View 时会反映在 UI 中。您已经在 BaseViewModel 中实现了“OnPropertyChanged”功能,但您似乎没有传递对象名称。

【讨论】:

  • 是的,BaseViewModel 类似。我按照您所说的尝试传递对象名称。但它并没有反映在 UI 中。
猜你喜欢
  • 2014-01-12
  • 1970-01-01
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2012-03-12
  • 2012-11-28
  • 1970-01-01
  • 2020-02-06
相关资源
最近更新 更多