Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
627 views
in Technique[技术] by (71.8m points)

xamarin.forms - How to change image source when a property changes through databinding in XAML from viewmodel in xamarin forms?

I am working on providing wishlist feature for my app by tapping wishlist icon on each product in list through MVVM. Once tapped, an API call is made to update database(add/remove from wishlist table). Based on result from api call, I updated the specific product's respective property to either 'True' or 'False'. Once property updated, I want to change the icon image source of corresponding product. I am using trigger on wishlist icon to differentiate non-wishlist and wiahlist products while binding the list itself.

My code is below,

MODEL

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; }
}

VIEWMODEL

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>

I am stuck at this place to change wishlist icon, when 'IsWishlistProduct' property value is changed in UpdateWishlist().


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Guessing through your code, the BaseViewModel contains code similar to the following:

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

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

And your viewmodel should be like this:

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

As Jason mentioned, If there is a change in data in the ViewModel, it is reflected in the UI when it is notified to the View through NotifyPropertyChanged. You already implemented "OnPropertyChanged" function in your BaseViewModel but it seems you don't pass the object name.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...