我正在创建一个带有图书库的应用程序。我可以将图书添加到库中,并且在重新构建应用程序时它们会正确显示。然而,我希望书在添加它们后立即出现在屏幕上,并想到通过使用可观察集合来实现这一点。
My collection view:
<CollectionView ItemsSource="{Binding Books}" Margin="36, 20" Grid.Row="1">
<CollectionView.ItemTemplate>
<DataTemplate>
<Border StrokeThickness="3" Margin="0, 0, 0, 4">
<Border.Stroke>
<LinearGradientBrush EndPoint="0,1">
<GradientStop Color="White" Offset="0.1" />
<GradientStop Color="{StaticResource Gray950}" Offset="1.0" />
</LinearGradientBrush>
</Border.Stroke>
<Grid HeightRequest="84">
<Image Aspect="AspectFill" Source="{Binding ThumbnailSource}"/>
<FlexLayout JustifyContent="Center" Direction="Column" HeightRequest="84" Margin="16">
<FlexLayout.Background>
<LinearGradientBrush EndPoint="0,1">
<GradientStop Color="#80000000" Offset="0.4"/>
<GradientStop Color="#00000000" Offset="0.9"/>
</LinearGradientBrush>
</FlexLayout.Background>
<Label FontSize="20" TextColor="White" Text="{Binding Title}" FontAttributes="Bold"/>
</FlexLayout>
</Grid>
</Border>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
My view model:
namespace eBooks.ViewModel
{
public partial class LibraryViewModel : ObservableObject
{
public LibraryViewModel()
{
BookService.OnBooksChanged += RefreshLibrary;
RefreshLibrary();
}
public void RefreshLibrary(List<Book> books = null)
{
using var db = new BooksContext();
_books = new ObservableCollection<Book>(db.Books);
}
[ObservableProperty]
ObservableCollection<Book> _books;
}
}
My Book模型
namespace eBooks.Models
{
[Table("Books")]
public class Book
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Title { get; set; }
public double Progress { get; set; }
public string ThumbnailData { get; set; }
public string AudioData { get; set; }
public string ThumbnailFormat { get; set; }
public string AudioFormat { get; set; }
private byte[] _thumbnailData = null;
public ImageSource ThumbnailSource
{
get
{
if (_thumbnailData == null || _thumbnailData.Length == 0 && ThumbnailData.Length != 0)
_thumbnailData = Convert.FromBase64String(ThumbnailData);
return ImageSource.FromStream(() => new MemoryStream(_thumbnailData));
}
}
}
}
处理EF Core数据库层操作的服务:
namespace eBooks.Services
{
public class BookService
{
public delegate void BooksChanged(List<Book> books);
public static event BooksChanged OnBooksChanged;
public void Add(Book book)
{
using var db = new BooksContext();
db.Books.Add(book);
db.SaveChanges();
OnBooksChanged?.Invoke(db.Books.ToList());
}
public void Delete(int id)
{
using var db = new BooksContext();
db.Books.Remove(db.Books.Single(book => book.Id == id));
db.SaveChanges();
OnBooksChanged?.Invoke(db.Books.ToList());
}
}
}
我尝试添加一个'refreshlibrary'方法,该方法在图书服务中调用OnBooksChanged
事件时运行,正如您在上面的代码中看到的那样。通过在方法中添加一个断点,我可以看到它在添加后包含了新添加的图书,但是UI仍然没有显示图书。
在您的情况下,ObservableCollection
与简单的List
相比没有优势。ObservableCollection
的优点是,如果您操作,它将通知与它绑定的控件的更改。集合的内容。这里,您不是在操纵_books
的内容,您是在为分配一个新的实例。每一次。假设一开始在_books
中有(Book1, Book2)
,我们把这个集合命名为A
,如果Book3
被添加到数据库中,你会给分配一个新的集合(Book1, Book2, Book3)
到_books
,我们将新集合命名为B
。注意,您没有在任何地方将Book3
添加到A
。现在,您的CollectionView
仍然绑定到没有更改的A
,因此不会收到更新通知。您所需要做的就是确保CollectionView
重新评估其绑定并绑定到B
。有几种方法可以做到这一点:
- 设置生成的属性而不是backing字段,因为它会自动调用
OnPropertyChanged
:
public void RefreshLibrary(List<Book> books = null)
{
using var db = new BooksContext();
Books = new ObservableCollection<Book>(db.Books);
}
- Call
OnPropertyChanged
:
public void RefreshLibrary(List<Book> books = null)
{
using var db = new BooksContext();
_books = new ObservableCollection<Book>(db.Books);
OnPropertyChanged("Books");
}
同样,您可以安全地将_books
的类型更改为List<Book>
,因为它不会在任何地方进行操作。