简体   繁体   中英

How to set listview itemssource to a viewmodel in Xamarin?

I'm trying to make a listview in xamarin show data from a restapi but have the option to filter the list or sort it based upon last name.

I've set the bindingcontext equal to the apiviewmodel which works. But I want to set the itemssource to a list which can be manipulated later instead of the binding context.

Here is the code that works:

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; }
}

This all works fine. It's only when I add the following lines that it stops displaying the data in the listview:

xaml.cs:

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

I think I need to add these lines so that I can manipulate the list that's being displayed. Why is the list not being displayed? Is this not how it should be done?

According to your description and code, you use MVVM to bind ListView firstly, it works fine, now you want to use Viewmodel to bind ListView itemsource in xaml.cs directly, am I right?

If yes,I do one sample according to your code, that you can take a look, the data can display successfully.

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; }
}

so I suggest you can check ContactsList if has data.

Update:

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

I do one sample that can meet your requirement, you can take a look:

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

在此处输入图片说明

在此处输入图片说明

So, to answer all your questions...


First, the binding.

Once you set the ItemsSource="{Binding ContactsList}" this means that anytime you signal that you have changed your ContactsList by calling OnPropertyChanged() , that is going to be reflected on the ItemsSource property (so, update the UI - that is why we put the OnPropertyChanged() into the setter). Thus, you do not need to manually set the ItemsSource every time you change it. (Especially from the View, as the View should have no knowledge of how the ContactsList is defined in the ViewModel.)

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


Next, the ordering and searching.

What OnPropertyChanged() does, is that it re-requests the bound property from the ViewModel, and updates the View according to that. So, just after OnPropertyChanged() is called, the getter of the bound property ( ContactsList ) is called by the View.

So, a good idea is to put the sorting mechanism into the getter of the public property. (Or the setter, when resetting the property.) Something like this:

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();
        }
    }
    //...
}

So, whenever your public property is called, it will sort the private property and return the collection that way.

Change public List<MainContacts> ContactsList to public ObservableCollection<MainContacts> ContactsList

in xaml.cs

instead of LocalList = LocalAPIViewModel.ContactsList; , put

ContactsList = new ObservableCollection(LocalAPIViewModel.ContactsList);

I think this will work, instead of setting ListView's Itemsource to 'LocalList'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM