简体   繁体   中英

How to call one viewmodel's method from another viewmodel

I am developing Windows Universal app. I have one GridView which has one textblock and a button. The gridview gets data of un-purchased objects from a service. The button is for purchasing particular object. So if user clicks on button that object is purchased & gridview gets refreshed to remove purchased item from it.

I am illustrating my requirement in simplified manner. I tried two ways, both are not working. Can you please suggest me solution regarding it.

First way I used is to inherit Model class with ViewModel class so I can access methods of ViewModel class, but it throws StackOverflowException in ViewModelBase at SetProperty<T> method.

PS - I don't want to migrate to any framework like MVVMLight, etc.

ViewModel.cs

public class ViewModel : ViewModelBase
{
    public ViewModel()
    {
        DataCollection = new ObservableCollection<Model>();
        for (int i = 1; i < 10; i++)
        {
            DataCollection.Add(new Model { Number = i });
        }
    }

    private ObservableCollection<Model> _DataCollection;
    public ObservableCollection<Model> DataCollection
    {
        get { return _DataCollection; }
        set { this.SetProperty(ref this._DataCollection, value); }
    }
}

Model.cs

public class Model : ViewModel
{
    public RelayCommand<int> DeleteCommand { get; set; }
    public Model()
    {
        DeleteCommand = new RelayCommand<int>((x) => DeleteNumber(x));
    }

    private void DeleteNumber(int x)
    {
        var obj = DataCollection.Where(varNum => varNum.Number == x).FirstOrDefault();
        if (obj != null)
        {
            DataCollection.Remove(obj);
        }
    }

    private int _Number;
    public int Number
    {
        get { return _Number; }
        set { this.SetProperty(ref this._Number, value); }
    }
}

2nd way I keep that isolated, so I was not able to access the methods.

ViewModel.cs is same as above

Model.cs

public class Model : ViewModelBase
{
    public RelayCommand<int> DeleteCommand { get; set; }
    public Model()
    {
        DeleteCommand = new RelayCommand<int>((x) => DeleteNumber(x));
    }

    private void DeleteNumber(int x)
    {
        // How to access ViewModel's DataCollection property or 
        // a method which sets un-purchased objects in  DataCollection property
    }

    private int _Number;
    public int Number
    {
        get { return _Number; }
        set { this.SetProperty(ref this._Number, value); }
    }
}

ViewModelBase.cs

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;
        this.OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
        {
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Well, in the first example you're getting a StackOverflowException because your ViewModel instantiates 9 Models each time - and since your Model is an extension of ViewModel, each one of those instantiates 9 more Models and an infinite recursion happens. That doesn't answer your main question, though :)

Your class names are confusing to me, because in MVVM a "Model" is simply a representation of the data and methods to manipulate it, whereas the ViewModel requests this data from the Model and presents it via publicly accessible properties that are retrieved from the View via binding. The View knows about the ViewModel, the ViewModel knows about the Model and the Model just knows about the data. In any case you shouldn't be binding directly from the View to the Model!

You'll want to house the RelayCommand in your ViewModel so your View can bind to it, and depending on what you want to happen when a user purchases an item (store it in a database, track this in another variable, simply remove from the view without doing anything else, etc.) you may or may not need to write additional logic for when this occurs. Generally you'll want the ViewModel to handle user input and update both the presentation object as well as notify the Model a change was made, if this is something your app requires. Think of it as the Model holds the actual data whereas the ViewModel only holds what the user sees.

Unfortunately, without knowing what you're trying to do in a little more detail it's hard to give more specific advice than this!

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