简体   繁体   中英

Set a Property in a ViewModel from Another ViewModel

I am trying to pass a value to a view model from another view model before navigating to the page attached to that view model. I was previously passing it to the view, then passing it to the view model. This seems like a clumsy way of doing things. I am not using any kind of framework so that is not an option. At the moment the property is set as static and this works but im not sure if this is good practice. The code:

View model 1:

This command opens the new page:

public void OpenRouteDetails()
{
   RouteStopPopOverViewModel.RouteName = "TestRoute";
   App.Page.Navigation.PushAsync(new RouteStopPopOverView());            
}

View model 2: (RouteStopPopOverViewModel)

public static string RouteName { get; set; }

This does work but I would prefer not to use static as a way to achieve this. Is there some way to set the RouteName property without using static or passing it through view-> view model. I have seen some answers about this but they don't seem to answer to question clearly.

here the sample you can achieve your requirement easily with navigation

public class ViewModelFrom : BaseViewModel
{
    async Task ExecuteCommand()
     {
        string routeName="value to trasfer";
        Navigation.PushAsync(new View(routeName));
     }
}


public partial class View : ContentPage
{
    public View(string routeName)
    {
        InitializeComponent();
        BindingContext = new ViewModelTo(routeName);
     }
}

public class ViewModelTo : BaseViewModel
{
    public string RouteName { get; set; }

    public ViewModelTo(string routeName)
    {
         RouteName=routeName;
    }
}

Share a controller class between view models.
The same instance has to be supplied to the constructor in both view models.
So you can set values, and listen for events in both view models.
The controller class becomes the intermediary.

public class SharedController : IControlSomething
{
    private string _sharedValue;

    public string SharedValue
    {
        get => _sharedValue;
        set
        {
            if (_sharedValue == value)
                return;

            _sharedValue = value;
            OnSharedValueUpdated();
        }
    }

    public event EventHandler SharedValueUpdated;

    protected virtual void OnSharedValueUpdated()
    {
        SharedValueUpdated?.Invoke(this, EventArgs.Empty);
    }
}

public class ViewModel1
{
    private readonly IControlSomething _controller;

    public ViewModel1(IControlSomething controller)
    {
        // Save to access controller values in commands
        _controller = controller;
        _controller.SharedValueUpdated += (sender, args) =>
        {
            // Handle value update event
        };
    }
}

public class ViewModel2
{
    private readonly IControlSomething _controller;

    public ViewModel2(IControlSomething controller)
    {
        // Save to access controller values in commands
        _controller = controller;
        _controller.SharedValueUpdated += (sender, args) =>
        {
            // Handle value update event
        };
    }
}

If there is a hierarchy you could express that in a parent to both of them.

public class Route
{
    private string Name;
}

public class RouteSelectedArgs : EventArgs
{
    public Route Selected { get; set; }
}

public interface IRouteSelection
{
    event EventHandler<RouteSelectedArgs> RouteSelected;
}

public interface IRouteDetails { }

public class RouteWizard
{
    public UserControl view { get; set; }

    private IRouteSelection _selection;
    private IRouteDetails _details;

    public RouteWizard(IRouteSelection selection, IRouteDetails details)
    {
        _selection = selection;
        _details = details;
        _selection.RouteSelected += Selection_RouteSelected;
        view = MakeView(_selection);
    }

    private void Selection_RouteSelected(object sender, RouteSelectedArgs e)
    {
        _selection.RouteSelected -= Selection_RouteSelected;
        view = MakeView(_details, e.Selected);

    }

    private UserControl MakeView(params object[] args)
    {
        ////magic
        throw new NotImplementedException();
    }
}

As you are using the MVVM pattern, you can use one of the many MVVM Frameworks to achieve this.

I use FreshMvvm and it allow me to pass parameters between view models like this

await CoreMethods.PushPageModel<SecondPageModel>(myParameter, false);

Then in SecondPageModel I can see access the parameters in the Init method

private MyParamType _myParameter;

public override void Init(object initData)
{
    base.Init(initData);

    var param = initData as MyParamType;
    if (param != null)
    {
        _myParameter = param;
    }
}

You can find more details about FreshMvvm here although most MVVM frameworks have similar functionality.

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