question

GordonS-9701 avatar image
0 Votes"
GordonS-9701 asked JessieZhang-2116 commented

Xamarin Forms CarouselView update property of current item

I have a CarouselView which is working and underneath is a panel of option buttons that apply to the current item in the CarouselView. One of those is a "Lock / Unlock" button.

The function of the button itself works fine and I'm able to toggle the state of the button (e.g. from Lock to Unlock).

What I would also like to do is change a property of the current item, to show / hide a small "padlock" icon (in a Frame). The CarouselView uses an ObservableCollection of "UserDevice". The frame, in the CarouselView DataTemplate has

IsVisible="{Binding IsLocked}"

but I can't get it to actually update (i.e. show / hide the padlock image).

How should I be approaching this? (I have tried so many different things and searched all sorts via Google).

dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

JessieZhang-2116 avatar image
0 Votes"
JessieZhang-2116 answered JessieZhang-2116 commented

Hello,


Welcome to our Microsoft Q&A platform!

The frame, in the CarouselView DataTemplate has

IsVisible="{Binding IsLocked}"

but I can't get it to actually update (i.e. show / hide the padlock image).

If you want to update the UI after you change the binded property, you can make your binded item implement interface INotifyPropertyChanged.

Take the official sample Xamarin.Forms - CarouselView for example , we can add property IsLocked in model Monkey.cs like this:

   public class Monkey: INotifyPropertyChanged
  {
     public string Name { get; set; }
     public string Location { get; set; }
     public string Details { get; set; }
     public string ImageUrl { get; set; }
     public bool IsFavorite { get; set; }

     // add variable here
    // public bool IsLocked { get; set; }
     private bool _isLocked;

     public bool IsLocked
     {
         set { SetProperty(ref _isLocked, value); }
         get { return _isLocked; }
     }

     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;

 }

And modify page VerticalTemplateLayoutPage.xaml, here we can add a button to hide or show the lock image.The code is:

 <StackLayout>
     <CarouselView ItemsSource="{Binding Monkeys}" x:Name="carouselView">
     <CarouselView.ItemsLayout>
         <LinearItemsLayout Orientation="Vertical" />
     </CarouselView.ItemsLayout>
     <CarouselView.ItemTemplate>
         <DataTemplate>
             <StackLayout>
                 <Frame HasShadow="True"
                        BorderColor="DarkGray"
                        CornerRadius="5"
                        Margin="20"
                        HeightRequest="300"
                        HorizontalOptions="Center"
                        VerticalOptions="CenterAndExpand">
                     <StackLayout>
                         <Label Text="{Binding Name}" 
                                FontAttributes="Bold"
                                FontSize="Large"
                                HorizontalOptions="Center"
                                VerticalOptions="Center" />

                             <StackLayout Orientation="Horizontal">
                                 <Image Source="{Binding ImageUrl}" 
                                Aspect="AspectFill"
                                HeightRequest="100"
                                WidthRequest="100"
                                HorizontalOptions="Center" />
                                 <!--bind property IsLocked here-->
                                 <Image Source="lock.png" IsVisible="{Binding IsLocked}" ></Image>

                                 <Button Text="lock"  Command="{Binding Source={x:Reference carouselView}, Path=BindingContext.LockCommand}"
                                                CommandParameter="{Binding}"/>

                             </StackLayout>

                             <Label Text="{Binding Location}"
                                HorizontalOptions="Center" />
                         <Label Text="{Binding Details}"
                                FontAttributes="Italic"
                                HorizontalOptions="Center"
                                MaxLines="5"
                                LineBreakMode="TailTruncation" />
                     </StackLayout>
                 </Frame>
             </StackLayout>
         </DataTemplate>
     </CarouselView.ItemTemplate>
 </CarouselView>
 </StackLayout>

Note: we add x:Name="carouselView" for current carouselView, and add command LockCommand in MonkeysViewModel.cs

     public ICommand LockCommand => new Command<Monkey>(ItemLockChanged);

     private void ItemLockChanged(Monkey obj)
     {
         CurrentMonkey = obj;
         CurrentItem.IsLocked = !CurrentItem.IsLocked;
     }

The result is:

92822-image.png

Note:
The data binding mechanism in Xamarin.Forms attaches a handler to this PropertyChanged event so it can be notified when a property changes and keep the target updated with the new value.

For more details, you can check:https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/xaml-basics/data-bindings-to-mvvm .

Best Regards,


Jessie Zhang


If the response is helpful, please click "Accept Answer" and upvote it.



Note: Please follow the steps in our [documentation][6] to enable e-mail notifications if you want to receive the related email notification for this thread.




image.png (66.7 KiB)
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks for the code. The only difference for me is that the button / command to lock/unlock is outside of the carousel (i.e. there isn't a button per item in the carousel) and acts on the Current Item of the carousel.

I implemented "PositionChanged" which stores the position in a property in the ViewModel. The LockUnlock Command uses that to get the item from the ObservableCollection of items, uses its values to do the lock/unlock and also updates the current item. Finally I put the updated item back into the ObservableCollection. After doing all of that, the Current Item in the CollectionView does not change (the lock icon does not change).

Do I need to do something else to make the CarouselView detect that the current item in the ObservableCollection has changed?

UPDATE: It's working! Had a bug in my code (oops!!)

0 Votes 0 ·

Have you implemented interface INotifyPropertyChanged for your item model and defined IsLocked as follows?

  private bool _isLocked;
  public bool IsLocked
  {
      set { SetProperty(ref _isLocked, value); }
      get { return _isLocked; }
  }
1 Vote 1 ·

Yes, I had that ... but my code that was setting the value of IsLocked had a bug, in that it always stayed the same!! As above, it is working now that I've fixed that.

Thanks very much for your help :-)

0 Votes 0 ·
Show more comments