How to update view based on a bindable property change. Creating a Star/heart/like "button"

JohnButlerJohnButler USMember ✭✭

I am trying to create a Star/heart/like "button"
I have a boolean called IsStared and a string, StarImageSource
StarImageSouce just looks at IsStared and sets a string source for one of 2 images based on IsStared.

I have a ViewCell that is part of a List that is in a ScrollView that has a bunch of Users Profiles. In that ViewCell I have a bindable property attached to an Image. That Image has a Gesture Recognizer that watches for taps. So it acts like a button but is just an image. I didn't want a button look with shadows, or have to create a custom button renderer as I am new to Xamarin and wanted to prototype faster. The problem is the star image does not automatically update once the value changes. I have to manually refresh the whole page to get it to work. I tried to use Invalidate or PostInvalidate. But those have to be in a view. I am handling all the Gesture Recognizing in the ContentPage.

I realize I am probable doing 10 things wrong here. But I have searched and searched and Have not found anything that helps me out in this specific situation.

Here is some code

public class NotOwnerProfile:Profile
{
public bool IsStared { get; set; }

    public string StarImageSource
    {
        get
        {
            if (IsStared)
                return "ic_star_green_900_48dp";
            return "ic_star_border_green_900_48dp";
        }
    }
}

Here is the bindable image part And this is
<ContentPage.Content>


ListView.ItemTemplate>


<Image Source="{Binding StarImageSource}"
x:Name="starButton"">
<Image.GestureRecognizers>

</Image.GestureRecognizers>

And this is in the HomePage.xaml.cs (I didnt post all the code so simplify) This is where the image is watching for gestures

    void OnTapGestureRecognizerTappedStarButton(object sender, EventArgs args)
    {
        var imageSender = (Image)sender;
        var notOwnerProfile = (NotOwnerProfile)imageSender.BindingContext;
        notOwnerProfile.IsStared = !notOwnerProfile.IsStared;
}

Best Answers

Answers

  • AlessandroCaliaroAlessandroCaliaro ITMember ✭✭✭✭✭
    Do You implement INotifyPropertyChanged?
  • JohnButlerJohnButler USMember ✭✭

    Nope. :neutral:

  • JohnButlerJohnButler USMember ✭✭

    Okay ill work on that.

    Something did click after I posted this and I did ad this line to the OnTapGestureRecognizerTappedStarButton methodd.

    imageSender.Source = notOwnerProfile.StarImageSource;

    so that it looks like this.

    void OnTapGestureRecognizerTappedStarButton(object sender, EventArgs args)
    {
    //tapCount++;
    var imageSender = (Image)sender;
    var notOwnerProfile = (NotOwnerProfile)imageSender.BindingContext;
    notOwnerProfile.IsStared = !notOwnerProfile.IsStared;
    imageSender.Source = notOwnerProfile.StarImageSource;
    }

    And it did make it work! Yippee! But can you let me know why this implementation is bad? I am sure its not good. And that the INotifyPropertyChanged is a better way to do it, but I want to know why. Thanks!

  • JohnButlerJohnButler USMember ✭✭

    Awesome, That was super informative. At first I was like I already know this stuff.... Oh, there is it... cool.

    But I have a question still, What is wrong with the way I did it?
    I set the imageSender.Source in the Gesture Recognizer. Does that break the MVVM structure? I don't see how that is any different than having the VM listen to the V and take is Imageview and then finding its binding context and changing its value. I am basically manually redoing the binding that happens at page creation. I get it is tightly coupled. But the whole thing seems tightly coupled. Setting the binding again doesn't seem to me to couple it any more tightly than it already is.

    I will implement the INotify solution. I am not trying to argue against that, it clearly seems like it is the correct way to do it. I only ask because I want to understand why doing it with INotify is better than the solution I figured out. Thanks!

Sign In or Register to comment.