0
votes

Details of my System is Operating System : Windows 10 Pro N Visual Studio Enterprise 2015 Xamarin.Forms 2.3.1..114

I have created a Tabbed view in which I am navigating to new page using Navigation.PushModalAsync method. In the view, I have a listview with custom Data Template. The Data Template is of ViewCell which contains two Images and one label.

What I am trying to do is when ever a cell is selected, I am showing the Image for checked row and when other row is selected then hiding the other row images and showing the currently selected image.

When first time view loads, I am setting the first row as selected and everything working good, but when I am selecting any other row then ListView is not refreshing. The Image IsVisible property is set correctly but it is not reflecting on the List.

See below code for reference

Code for the ListView

var listView = new ListView();
listView.ItemsSource = StaticData.ListData;
listView.ItemTemplate = new DataTemplate(typeof(CustomDataCell));
listView.VerticalOptions = LayoutOptions.FillAndExpand;
listView.BackgroundColor = Color.White;            
listView.SeparatorVisibility = SeparatorVisibility.Default;
listView.RowHeight = 30;
listView.SeparatorColor = Color.White;
listView.ItemTapped += (sender, e) =>
                {
                if (e == null) return;
                selectedValue = (e.Item as ValiditySchema).Value;
                SelectValidityItem(listView,selectedValue); // In this method I am setting the IsSelected property to true  and other rows IsSelected property to false.                
                };

Code for CustomDataCell

public class CustomDataCell : ViewCell
{
    public Label CellText { get; set; }
    public BoxView ImageDetail { get; set; }
    public Image CheckedImage { get; set; }
    public CustomDataCell()
    {
        CellText = new Label();
        CellText.FontAttributes = FontAttributes.Bold;
        CellText.SetBinding(Label.TextProperty, "Text");
        CellText.VerticalOptions = LayoutOptions.Center;
        CellText.HorizontalOptions = LayoutOptions.Start;
        CellText.TextColor = Color.Black;
        ImageDetail = new BoxView();
        ImageDetail.WidthRequest = 20;
        ImageDetail.HeightRequest = 10;
        ImageDetail.SetBinding(BoxView.BackgroundColorProperty, "ColorName");
        //declaring image to show the row is selected
        CheckedImage = new Image();
        CheckedImage.Source = "Images/checked.png";
        CheckedImage.HorizontalOptions = LayoutOptions.CenterAndExpand;
        CheckedImage.VerticalOptions = LayoutOptions.Center;
        CheckedImage.SetBinding(Image.IsVisibleProperty, "IsSelected");

        var ContentCell = new StackLayout();
        ContentCell.Children.Add(ImageDetail);
        ContentCell.Children.Add(CellText);
        ContentCell.Children.Add(CheckedImage);
        ContentCell.Spacing = 5;
        ContentCell.Orientation = StackOrientation.Horizontal;
        var maiCell = new StackLayout();
        maiCell.Orientation = StackOrientation.Vertical;
        maiCell.Children.Add(ContentCell);      
        View = maiCell;

    }
}
1

1 Answers

2
votes

In order for the ListView to know that items in your ItemsSource have changed you need to raise a INotifyPropertyChanged event on that specific item.

Usually instead of binding the data directly to the ListView, you would rather have a ViewModel representation for each item, following the MVVM pattern:

View <-> ViewModel <-> Model

So what you need to do is to create a ViewModel for your items in StaticData.ListData:

public class ListItemViewModel : INotifyPropertyChanged
{
    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set {
            _isSelected = value;
           OnPropertyChanged();
        }
    }

    // more properties here...

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Then you can bind the IsSelected property to your image's Visibility property.

This way when you change IsSelected in your ViewModel, the correct event gets fired and the ListView now knows that something changed and that it needs to refresh the view.