Xamarin:在后台更新ObservableCollection

时间:2018-04-09 05:10:33

标签: xamarin mvvm observablecollection

我有一个基于由ObservableCollection< Item>填充的Listview的Xamarin.Forms应用程序。并绑定到一个公开为List< Item>的SQLite模型。

现在我很难弄清楚如何通过网络更新数据。

整个过程应该在后台运行。如果所有内容都按预期运行,则更新过程将基于异步...等待任务,新项目会在拉入时逐个显示在屏幕上。

有人可以指导我如何布置我的应用程序以及如何实现这样的后台更新任务吗?

注意:

更有经验的同事警告我,这样的概念根本不能在Xamarin中完成,因为他们说,ObservableCollection“不支持由后台任务更新”。我对此做了一些研究,发现确实有一些迹象表明这可能是真的,但这些信息已经过时(从2008年开始),事情很可能从那时起发生了变化。

出于性能原因,我不能简单地拉入完整列表并丢弃现有列表,但我需要实现基于记录的更新,逐个查看项目。要完成此记录,必须具有唯一的ID,并且有时间戳。我的应用程序知道它上次看到Web服务的时间,并且可以查询自那时以来已更改的所有项目。我已经有一个REST服务从后端作为List提取已更改的Items数据,但无法弄清楚如何刷新ObservableCollection和底层数据库。

1 个答案:

答案 0 :(得分:0)

我对ListView进行了所有更新。在这里,我在列表视图中有一个按钮,单击该按钮时会更新属性,该属性通过将其保存到sql数据库中而得以保留。假定您已建立数据库。

数据库: 更新项目(如果存在)或保存新项目的功能。这是一个任务,因此可以异步调用。

   public Task<int> SaveItemAsync(Item item)
    {
        if(item.ItemId != 0)
        {
            return database.UpdateAsync(item);
        }
        else
        {
            return database.InsertAsync(itme);
        }
    }

Xaml

  • 列表视图,该视图绑定到从项目数据库创建的Observable集合。
  • GestureRecognizers在图像上设置并绑定到ViewModel中的tapCommand-Xaml后面的代码定义了绑定上下文

后面的代码

 ItemViewModel viewModel;
    public MessagePage ()
    {
        InitializeComponent ();
        viewModel = new ItemViewModel();
        BindingContext = viewModel;
    }

然后是Xaml

  • 绑定到ObsevableCollection“ ItemsPassed”,并将其设置为其中的绑定上下文。因此,您需要返回到 页面BindingContext,因此请注意TapCommand的绑定路径。
  • 将ItemId作为参数传递

    <ListView ItemsSource="{Binding ItemsPassed}"
                      HasUnevenRows="True"
                      x:Name="ItemListView">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ContentView>
                                <StackLayout Padding="20">
                                    <StackLayout Orientation="Horizontal">
                                        <StackLayout Orientation="Vertical" HorizontalOptions="Start">
                                            <Label Text="{Binding ItemText}"
                                                   FontAttributes="Bold"/>
                                        </StackLayout>
                                        <Image Source="{Binding Favourited,  HeightRequest="12" HorizontalOptions="EndAndExpand">
                                            <Image.GestureRecognizers>
                                                <TapGestureRecognizer 
                                                    Command="{Binding Path=BindingContext.TapCommand, Source={x:Reference ItemListView}}" 
                                                    CommandParameter="{Binding ItemId}"/>
                                            </Image.GestureRecognizers>
                                        </Image>
                                    </StackLayout>
                                </StackLayout>
                            </ContentView>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

ViewModel

  • 定义ICommand并为其分配功能
  • 在可观察的集合中查找项目并更改属性
  • 还需要使用await App.Database.SaveItemAsync(item)在数据库中对此进行更改-因此,命令调用的函数必须是异步的

public class ItemsViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Item> ItemsPassed { get; set; } = new ObservableCollection<Item>();
    // Get items out of yourdatabase 
    public async void GetItems()
    {
        List<Item> itemsOut = await App.Database.GetItemsAsync();
        foreach (Item i in itemsOut)
        {
            ItemsPassed.Add(i);
        }
    }
    ICommand tapCommand;
    public ItemsViewModel()
    {
        GetItems();
        tapCommand = new Command(ExecuteTap);
    }
    public ICommand TapCommand
    {
        get { return tapCommand; }
    }
    // Find the item selected and change the property
    private async void ExecuteTap(object obj)
    {
        var item = ItemsPassed.FirstOrDefault(i => i.ItemId.ToString() == obj.ToString());
        if (item != null)
        {
            if (item.Favourited == true)
            {
                item.Favourited = false;
            }
            else
            {
                item.Favourited = true;
            }
            await App.Database.SaveItemAsync(item);
            Console.WriteLine("update the database");
        }
    }
}

然后,您要确保更改在视图中发生-这是通过在Model中扩展INotifyPropertyChange并在属性更改时调用它来完成的。

模型

  • 在视图模型中更改项目时,将触发OnPropertyChanged,从而导致视图更新。

    public class Item : INotifyPropertyChanged
    

    {     [PrimaryKey,自动递增]     public int ItemId {get;组; }     公共字符串ItemText {get;组; }     公共字符串Author {get;组; }

    private bool _favourited;
    public bool Favourited
    {
        get { return _favourited; }
        set
        {
            _favourited = value;
            OnPropertyChanged("Favourited");
        }
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

希望这会有所帮助。抱歉,我不得不在代码段中添加一些内容,代码段无法正常运行,可能是因为某些代码是错误的,但这仅是示例。