简体   繁体   中英

How to add to ObservableCollection with MVVM C#

I'm making a xamrin.forms application with tabbed pages containing some listviews. So I decided to try the MVVM approach, but I've never done that before. I have tried to learn from various online tutorials, and I get the concept, but there are some thing I'm missing apparently.

I want the user to be able to add to the list with the click of a button, but I just don't know how to do it.

The Model contains a class called ConnectedProjectors:

public class ConnectedProjectors
{
    public string ipaddress { get; set; }
    public string version { get; set; }
    public string swversion { get; set; }

    public Color activeStatus { get; set; }


    public override string ToString()
    {
        return ipaddress;
    }

}

In ViewModel I have a 2 classes ProjectorViewModel which inherits from ViewModelBase:

 public class ProjectorViewModel : ViewModelBase
{
    private ProjectorServices service;


    public ProjectorViewModel()
    {
        service = new ProjectorServices();
        ProjectorList = new ObservableCollection<ConnectedProjectors>();
        ProjectorList = service.GetProjectors("test", "test", "test", Color.White); //Works as expected
    }

    public void AddProjector(string ip, string ver, string sw, Color color)
    {
        ProjectorList = service.GetProjectors(ip, ver, sw, color); //I expected this to add to the list
    }


    private ObservableCollection<ConnectedProjectors> connectedProjectors;
    public ObservableCollection<ConnectedProjectors> ProjectorList
    {
        get { return connectedProjectors; }
        set { SetProperty(ref connectedProjectors, value); } // Maybe the NotifyEvent doesn't work as expected?
    }

}

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value,
        [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged(string propertyName)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

plus the ProjectorServices class:

 class ProjectorServices
{
    public ProjectorServices()
    {

    }

    public ObservableCollection<ConnectedProjectors> GetProjectors(string ipad, string ver, string sw, Color color)
    {
        var list = new ObservableCollection<ConnectedProjectors>
        {
            new ConnectedProjectors
            {
                ipaddress = ipad,
                version = ver,
                swversion = sw,
                activeStatus = color                   
            }
        };

        return list;
    }
}

and finally the MainPage class:

   public partial class MainPage : ContentPage
{
    public ConnectedProjectors projectors;
    private ProjectorViewModel projvm = new ProjectorViewModel();
    public MainPage()
    {
        InitializeComponent();

        this.BindingContext = new ProjectorViewModel();
    }
     public void AddProj(object sender,EventArgs e)
    {
        string ip = txt.Text;  // text input in editor in MainView view.
        string pn = "Not Found";
        string sw = "Not Found";
        Color col = Color.Chocolate;

        try
        {
            pn = GetPartNr(ip); // Sends an ascii command to see if the ipaddress returns an expected result
            sw = GetSWVersion(ip);
            col = GetActiveStatus(ip);
        }

        finally
        {
            projvm.AddProjector(ip, pn, sw, col);
        }
    }
}

The result of the code as it is now, is that the command in ProjectorViewModel() method adds to the Observable collection as the application initializes as expected. But in the method AddProjector() that I wrote just below, the same command does not add a new item to the collection (At least not visible in listview).

in XAML I have listview ItemSource bound to ProjectorList, and the listview shows the test item, but when I click the button that fires the AddProj()Method, nothing happens.

I expect that the issue is one of two things:

  1. The way I try to add to collection is not correct

  2. The PropertyChanged doesn't work as expected

I was hoping someone could help me with this. Any help would be very much appreciated.

You are correct in what the issue is. Your MainPage has its BindingContext set to a new instance of ProjectorViewModel .

this.BindingContext = new ProjectorViewModel();

However, AddProj method adds the new ViewModel to projvm , which is just a private field, sitting there. It has no connection whatsoever to the page and its binding. A better approach is to expose your BindingContext's ViewModel in a property and use it.

public ProjectorViewModel ViewModel
{
    get => this.BindingContext as ProjectorViewModel;
    set => this.BindingContext = value;
}

And then you can set your BindingContext like this:

public HomePage()
{
    InitializeComponent();

    this.ViewModel = new ProjectorViewModel();
}

This way we have set up again our context, but this time we have access to it. Now, you can add your new ViewModel like this:

this.ViewModel.AddProjector(ip, pn, sw, col);

Now you will be using the same instance, that your page has been bound to.

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