如何将 ListView 绑定到集合并实时刷新
Posted
技术标签:
【中文标题】如何将 ListView 绑定到集合并实时刷新【英文标题】:How to bind ListView to a collection and refresh it real time 【发布时间】:2019-11-05 23:50:58 【问题描述】:我正在将我的 ListView 绑定到我的 Realm 数据库,但是当我向其中添加新项目时它不会刷新它。我正在使用另一个页面添加新项目。
我在这里作为参考:https://help.syncfusion.com/xamarin/sflistview/mvvm#binding-itemssource
我的模特:
public class Category : RealmObject
[PrimaryKey]
public string CategoryID get; set; = Guid.NewGuid().ToString();
public string CategoryTitle get; set;
public string CategoryDetails get; set;
[Backlink(nameof(Note.CategoryOfNote))]
public IQueryable<Note> Notes get;
public string CategoryIcon get; set;
public bool IsExpanded get; set;
我的 XAML 文件包含 ListView
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="NEWCAT"
Clicked="NewCat_Clicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<ListView x:Name="categoryList"
ItemsSource="Binding Categories"
ItemTapped="ListView_ItemTapped"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical"
HorizontalOptions="FillAndExpand"
Padding="10"
Spacing="10">
<Label Text="Binding Path=CategoryTitle"
FontSize="Medium"/>
<StackLayout IsVisible="Binding IsExpanded"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Button Text="Notes"
Clicked="NotesButton_Clicked" />
<Button Text="Edit"
Clicked="EditButton_Clicked"/>
<Button Text="Delete"
Clicked="DeleteButton_Clicked"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
还有我的 ViewModel (DBServices.GetCategories 是一个静态方法,它从 Realm DB 中返回一个类别的集合。BaseViewModel 实现了 INotifyPropertyChanged)
class MainViewModel : BaseViewModel
private Category _oldCategory;
public MainViewModel()
RefreshCategories();
private void RefreshCategories()
Categories = new ObservableCollection<Category>(DBServices.GetCategories());
private ObservableCollection<Category> _Categories;
public ObservableCollection<Category> Categories
get
return _Categories;
set
_Categories = value;
OnPropertyChanged("Categories");
这是 BaseViewModel 类中的 OnPropertyChanged 方法
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
当我单击工具栏按钮时,它会推送一个新表单页面以创建一个新类别。然后它只是将该类别添加到 Realm DB 中。之后它会自行弹出。但我的 ListView 没有任何变化。
编辑:当我重新启动应用程序时,我可以在 ListView 中看到新项目。但我希望在添加它们时将其列出。
【问题讨论】:
所以您在另一个页面中将对象添加到数据库中,然后弹出并期望 MainPage 更新列表视图? @BrunoCaceiro 是的。它仅在应用程序重新启动后更新列表。 【参考方案1】:您可以使用 Xamarin 表单 MessagingCenter 告诉 ListView 它需要更新。
在将新类别添加到 Realm DB 的页面上,在添加类别之后但在页面弹出之前的某个时间,您会发送一条消息告诉 ListView 页面进行更新。这可能看起来像:
MessagingCenter.Send(this, "Update listview");
在您的 MainViewModel 中,您需要订阅该消息,然后对其进行操作。这可能是这样的:
MessagingCenter.Subscribe<AddCategoryPage>(this, "Update listview", (sender) =>
RefreshCategories();
);
使用 MessagingCenter 时需要注意的两点。
-
发送者和订阅者之间传递的消息必须相同。在这种情况下,消息是“更新列表视图”。因为它必须相同,所以您可能希望在单独的类中定义消息,以便发送者和订阅者都可以引用它。
订阅消息时,您必须确保取消订阅。一种流行的模式是在页面出现时订阅,在页面消失时取消订阅。不过,不同的模式可能更适合您。
附带说明,您不需要Categories
的完整属性定义。 ObservableCollection
将在添加或删除项目时处理通知。只需设置一次Categories = new ObservableCollection<Category>();
,然后只添加或删除项目。您无需在每次 DB 调用时都对其进行更新。
【讨论】:
感谢您的回答。我试过了,但是 ListView 没有改变。 等等,它有效!再次感谢你。但是我还是很疑惑,为什么要发消息让它刷新呢? “绑定”应该是自动完成的,不是吗? @FarukD ListView 被“绑定”到 Categories 属性,但是更新 Categories 属性是什么?您只需在一处更新 Categories 属性位置,即 RefreshCategories 方法,并且您只需在页面的构造函数中调用 RefreshCategories 方法。因此,类别仅在构建页面时才会更新。您必须告诉列表检查更新的数据。【参考方案2】:要仅测试 XAML 和 ViewModel,请尝试在 ViewModel 中将 DBServices.GetCategories()
替换为以下内容:
public static IEnumerable<Category> TestCategories
get
yield return new Category CategoryTitle = "title 1" ;
yield return new Category CategoryTitle = "title 2" ;
...
public MainViewModel()
Categories = new ObservableCollection<Category>(TestCategories);
DBServices.GetCategories()
还应测试预期输出,此处未显示。
【讨论】:
感谢您的回答。我可以使用此代码在我的 ListView 中看到标题 1 和标题 2。我知道 DBServices.GetCategories() 返回预期的输出,因为当我重新启动应用程序时,我可以看到我添加的新类别。以上是关于如何将 ListView 绑定到集合并实时刷新的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 ListView 数据绑定到可观察集合不能正确显示