如何将 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&lt;Category&gt;();,然后只添加或删除项目。您无需在每次 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绑定到一个集合,如何访问父类中的事件?

c#将list集合直接绑定到listview控件

可观察集合的 C# wpf listview 绑定问题

为啥我的 ListView 数据绑定到可观察集合不能正确显示

Xamarin Forms ListView 绑定到 Observable 集合中的子对象列表

Android:重新绑定 ListView 或 RecyclerView 而不刷新 Header