1

I've got a CollectionView containing an ImageButton. When the image is pressed I replace a.png with b.png.

This is working fine but when I scroll down the list, every 10th item is now showing b.png!

If instead of setting the button.source, I called the line below again after saving to the DB which solves my problem but then I start at the top of the list and not at the current position I was at:

ItemsListView.ItemsSource = items;

How can I set the button.source without it creating this bug on every 10th item?

    <CollectionView x:Name="Items">
                <CollectionView.ItemTemplate>
                        <DataTemplate>
                           <ImageButton CommandParameter="{Binding Id}" Source="a.png" Clicked="OnInventoryClicked" />
                        </DataTemplate>
                    </CollectionView.ItemTemplate>
    </CollectionView>
    void OnInventoryClicked(object sender, EventArgs e)
            {
                    var button = (sender as ImageButton);
                    var itemId = button.CommandParameter.ToString();
                    var inventoryItem = await App.Database.GetItemAsync(itemId);
                    inventoryItem.IsInInventory = !inventoryItem.IsInInventory;
                    await App.Database.SaveItemAsync(inventoryItem);
                    button.Source = inventoryItem.IsInInventory? "b.png" : "a.png";         
            }
Cfun
  • 8,442
  • 4
  • 30
  • 62
KevinUK
  • 5,053
  • 5
  • 33
  • 49
  • side question : shouldn't CommandParameter be used with Command only (don't see Command) ? – Cfun Feb 02 '21 at 22:13
  • 2
    instead of directly modifying the image source, try binding it to a model property – Jason Feb 02 '21 at 22:14
  • also, you should not need to load the item every time. You already have a copy that is bound to the current cell, just use that and save yourself a db operation – Jason Feb 02 '21 at 22:15
  • Thanks, it's my first Xamarin app so I need to read more tutorials but it's working now with adding the binding on the image source. How could I refactor to remove CommandParameter and remove the 'get DB call' while still being able to get hold of the full object to pass to the 'save DB call'? – KevinUK Feb 02 '21 at 23:03
  • 1
    `CommandParameter="{Binding .}"` will pass the entire object, not just the ID – Jason Feb 03 '21 at 01:34

1 Answers1

2

You could change with the souce property.

Xaml:

<CollectionView x:Name="Items" ItemsSource="{Binding infos}">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <!--<ImageButton
                Clicked="OnInventoryClicked"
                CommandParameter="{Binding Id}"
                Source="a.png" />-->
            <ImageButton Clicked="ImageButton_Clicked" Source="{Binding image}" />
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

Code behind:

public partial class MainPage : ContentPage
{

    public ObservableCollection<Info> infos { get; set; }
    public MainPage()
    {
        InitializeComponent();
        infos = new ObservableCollection<Info>()
        {
            new Info{image = "pink.jpg"        },
            new Info{image = "pink.jpg"        },
            new Info{image = "pink.jpg"        },
            new Info{image = "pink.jpg"        },
            new Info{image = "pink.jpg"        },

        };


        this.BindingContext = this;
    }

    private void ImageButton_Clicked(object sender, EventArgs e)
    {
        var button = (sender as ImageButton);
        button.Source = "dog.jpg";
    }


}
public class Info
{
    public string image { get; set; }
}
Wendy Zang - MSFT
  • 10,509
  • 1
  • 7
  • 17