如何在 Xamarin 中将 listview itemssource 设置为 viewmodel?

How to set listview itemssource to a viewmodel in Xamarin?

我正在尝试在 xamarin 中创建一个列表视图以显示来自 restapi 的数据,但可以选择过滤列表或根据姓氏对其进行排序。

我已将 bindingcontext 设置为等于有效的 apiviewmodel。但是我想将 itemssource 设置为一个可以在以后操作的列表,而不是绑定上下文。

这是有效的代码:

Xaml:

<ListView x:Name="DirectoryListView" ItemsSource="{Binding ContactsList}" IsPullToRefreshEnabled="True">

Xaml.cs:

LocalAPIViewModel = new APIViewModel();
BindingContext = LocalAPIViewModel;

APIViewModel.cs:

private List<MainContacts> _ContactsList { get; set; }
public List<MainContacts> ContactsList
    {
        get
        {
            return _ContactsList;
        }
        set
        {
            if(value != _ContactsList)
            {
                _ContactsList = value;
                NotifyPropertyChanged();
            }
        }
    }

public class MainContacts
{
    public int ID { get; set; }
    public string FirstName { get; set; }
}

一切正常。只有当我添加以下行时,它才会停止在列表视图中显示数据:

xaml.cs:

LocalList = LocalAPIViewModel.ContactsList;
DirectoryListView.ItemsSource = LocalList;

我想我需要添加这些行,以便我可以操作正在显示的列表。为什么不显示列表?这不应该是这样吗?

public List<MainContacts> ContactsList更改为public ObservableCollection<MainContacts> ContactsList

xaml.cs

而不是LocalList = LocalAPIViewModel.ContactsList;,把

ContactsList = new ObservableCollection(LocalAPIViewModel.ContactsList);

我认为这会起作用,而不是将 ListView 的 Itemsource 设置为 'LocalList'

根据你的描述和代码,你先用MVVM绑定ListView,效果很好,现在你想用Viewmodel直接绑定xaml.cs中的ListView itemsource,对吗?

如果是的话,我按照你的代码做了一个例子,你可以看看,数据可以显示成功。

public partial class Page4 : ContentPage
{
    public APIViewModel LocalAPIViewModel { get; set; }
    public Page4 ()
    {
        InitializeComponent ();
        LocalAPIViewModel = new APIViewModel();           
        listview1.ItemsSource = LocalAPIViewModel.ContactsList;
    }
}

public class APIViewModel
{
    public ObservableCollection<MainContacts> ContactsList { get; set; }
    public APIViewModel()
    {
        loadddata();
    }

    public void loadddata()
    {
        ContactsList = new ObservableCollection<MainContacts>();
        for(int i=0;i<20;i++)
        {
            MainContacts p = new MainContacts();
            p.ID = i;
            p.FirstName = "cherry"+i;
            ContactsList.Add(p);
        }
    }
}
public class MainContacts
{
    public int ID { get; set; }
    public string FirstName { get; set; }
}

所以我建议你可以查看ContactsList是否有数据。

更新:

I want to be able to search the list with a search bar and also order it by first or last names. I also want to be able to click on one of the contacts and open up a separate page about that contact

我做了一个样品,可以满足你的要求,你可以看看:

https://github.com/851265601/xf-listview

所以,回答你所有的问题...


首先是绑定。

一旦你设置了 ItemsSource="{Binding ContactsList}" 这意味着任何时候你通过调用 OnPropertyChanged() 发出你已经改变你的 ContactsList 的信号,这将反映在 ItemsSource 属性(因此,更新 UI - 这就是我们将 OnPropertyChanged() 放入 setter 的原因)。因此,您无需在每次更改时手动设置 ItemsSource。 (特别是从 View 来看,因为 View 应该不知道 ContactsList 是如何在 ViewModel 中定义的。)

So you can completely remove those lines from the View's code-behind.


接下来是排序和搜索。

OnPropertyChanged() 的作用是,它从 ViewModel 重新请求绑定 属性,并据此更新视图。因此,就在 OnPropertyChanged() 被调用之后,绑定 属性 (ContactsList) 的 getter 被视图调用。

所以,一个好主意是把排序机制放到public属性的getter中。 (或重置 属性 时的 setter。)像这样:

public class ViewModel {
    private ObserveableCollection<MainContacts> contactList { get; set; }
    public ObserveableCollection<MainContacts> ContactList {
        get {
            return new ObservableCollection<MainContacts>(contactList
                .Where(yourFilteringFunc)
                .OrderBy(yourOrderingFunc));
        }
        set {
            contactsList = value;
            OnPropertyChanged();
        }
    }
    //...
}

因此,无论何时调用 public 属性,它都会以这种方式对私有 属性 和 return 集合进行排序。