xamarin help, Error in collectionview property change

RaphaelZhang 1 Reputation point
2021-03-30T12:35:51.857+00:00

I need to write a page that can scroll through a list of many comics. Each comics shows summary information, such as cover thumbnail, book title and author. At the top of the page, there is a book type label that you can click. Every time you click the book type label, the comic list will be refreshed.

Because all the information of books is pulled asynchronously from the network, it is necessary to update the pulled title or cover thumbnail in time in the comic list. Of course, I have set the properties that need to be refreshed asynchronously to PropertyChanged.

The problem is, when the comic list is displayed for the first time, I see that the information of the book is constantly updated. However, when I switch the book type label, the update ability fails, and the Handler of the book triggering PropertyChanged is null.

The number of books is updated correctly, but the summary of each book cannot be updated.

I'm using CollectionView.

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,288 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. JarvanZhang 23,936 Reputation points
    2021-03-30T14:14:07.053+00:00

    Hi, 40317169. How did you create the model class and viewModel class? Please make sure the 'summary' property raise the PropertyChanged event when the value is changed.

    Here is the related code about the viewModel class in my test sample, you could refer to it.

    public class BookViewModel : INotifyPropertyChanged
    {
        public BookViewModel()
        {
            BookInfo = xxx;
    
            DataCollection = new ObservableCollection<BookModel>();
            //add the data
        }
        public ObservableCollection<BookModel> DataCollection { get; set; }
    
        private string bookInfo;
        public string BookInfo
        {
            get
            {
                return bookInfo;
            }
            set
            {
                if (bookInfo != value)
                {
                    bookInfo = value;
                    NotifyPropertyChanged();
                }
            }
        }
    
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    
    1 person found this answer helpful.

  2. RaphaelZhang 1 Reputation point
    2021-03-31T03:01:22.723+00:00

    This is my XAML, just the key part:

            <CollectionView ItemsSource="{Binding BookList}"
                            IsGrouped="False" 
                            ItemsLayout="VerticalGrid, 3"
                            SelectionChanged="OnTouchBook"
                            SelectionMode="Single"
                            x:Name="CV">
    
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Grid Padding="2">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="150" />
                                <RowDefinition Height="15" />
                                <RowDefinition Height="12" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="100" />
                            </Grid.ColumnDefinitions>
                            <Image Grid.Row="0" 
                                   Source="{Binding CoverThumb}"
                                   Aspect="AspectFill"
                                   HeightRequest="150" 
                                   WidthRequest="100" />
                            <Label Grid.Row="1" 
                                   Text="{Binding Name}" 
                                   FontSize="12"
                                   TextColor="Black"
                                   VerticalOptions="Center"/>
                            <Label Grid.Row="2"
                                   Text="{Binding Author}"
                                   FontAttributes="Italic" 
                                   FontSize="10"
                                   TextColor="#8F8F8F"
                                   VerticalOptions="Start"/>
                        </Grid>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
    

    ViewModel:

       public class RemoteViewModel : INotifyPropertyChanged
        {
            private readonly Dictionary<int, BookModel> DictBooks = new Dictionary<int, BookModel>();
    
    
            public RemoteViewModel(ICommand _cmd)
            {
                BookList = new ObservableCollection<BookModel>();
            }
    
    
    
            private ObservableCollection<BookModel> _BookList;
            public ObservableCollection<BookModel> BookList
            {
                get { return _BookList; }
                set
                {
                    if (value != _BookList)
                    {
                        _BookList = value;
                        NotifyPropertyChanged("BookList");
                    }
                }
            }
    
    
    
            public void SelectedLabel(string label)
            {
                if (label == "全部")
                {
                    LabelSelected = label;
    
                    BookList?.Clear();
                    BookStore.ForEachLabel((label_name, label_list) =>
                    {
                        foreach (ComicBook book in label_list)
                        {
                            BookModel model = new BookModel(book) { Store = BookStore, };
    
                            BookList?.Add(model);
    
                            if (!DictBooks.ContainsKey(model.ID))
                                DictBooks.Add(model.ID, model);
                        }
    
                        return true;
                    });
    
    
                }
                else if(BookStore.TryGetBookList(label, out List<ComicBook> comics))
                {
                    LabelSelected = label;
    
                    BookList?.Clear();
    
                    foreach (ComicBook book in comics)
                    {
                        BookModel model = new BookModel(book) { Store = BookStore, };
    
                        BookList?.Add(model);
    
                        if (!DictBooks.ContainsKey(model.ID))
                            DictBooks.Add(model.ID, model);
                    }
    
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    

    Model:

      public class BookModel : INotifyPropertyChanged
        {
            public BookStore Store { get; set; }
    
            private string _Name;
            public string Name
            {
                get { return _Name; }
                private set
                {
                    if (value != _Name)
                    {
                        _Name = value;
                        NotifyPropertyChanged("Name");
                    }
                }
            }
    
            private int _ID;
            public int ID
            {
                get { return _ID; }
                private set
                {
                    if (value != _ID)
                    {
                        _ID = value;
                        NotifyPropertyChanged("ID");
                    }
                }
            }
    
            private string _Author;
            public string Author
            {
                get 
                {
                    if (string.IsNullOrEmpty(_Author)) return "无";
                    else return _Author; 
                }
                private set
                {
                    if (value != _Author)
                    {
                        _Author = value;
                        NotifyPropertyChanged("Author");
                    }
                }
            }
    
            private string _Editor;
            public string Editor
            {
                get
                {
                    if (string.IsNullOrEmpty(_Editor)) return "无";
                    else return _Editor;
                }
                private set
                {
                    if (value != _Editor)
                    {
                        _Editor = value;
                        NotifyPropertyChanged("Editor");
                    }
                }
            }
    
            private string _EditDate;
            public string EditDate
            {
                get
                {
                    if (string.IsNullOrEmpty(_EditDate)) return "无";
                    else return _EditDate;
                }
                private set
                {
                    if (value != _EditDate)
                    {
                        _EditDate = value;
                        NotifyPropertyChanged("EditDate");
                    }
                }
            }
    
            public string _Desc;
            public string Desc
            {
                get
                {
                    if (string.IsNullOrEmpty(_Desc)) return "无";
                    else return _Desc;
                }
                private set
                {
                    if (value != _Desc)
                    {
                        _Desc = value;
                        NotifyPropertyChanged("Desc");
                    }
                }
            }
    
            public ImageSource CoverThumb
            {
                get
                {
                    if (Comic.NoAbstract)
                    {
                        Store.RefreshBookAbstract(Comic.ID);
                        return null;
                    }
                    else if (Comic.Cover != null && Store.TryReadThumbnails(Comic.Cover, out MemoryStream thumb1))
                        return ImageSource.FromStream(() => { return thumb1; });
                    else if (Comic.Cover == null && Store.TryReadThumbnails(Comic.GetPage(0), out MemoryStream thumb2))
                        return ImageSource.FromStream(() => { return thumb2; });
                    else return null;
                }
                private set{ NotifyPropertyChanged("CoverThumb"); }
            }
    
            public ComicBook Comic { get; private set; }
    
            public BookModel(ComicBook comic) { Refresh(comic); }
    
            public void Refresh(ComicBook comic)
            {
                Name = comic.BookName; 
                ID = comic.ID; 
                Author = comic.BookAuthor; 
                Comic = comic;
                Editor = comic.BookEditor;
                EditDate = comic.EditDate.ToString("D");
                Desc = comic.Describe;
            }
    
            public void RefreshCoverThumb() { CoverThumb = null; }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }