send parameter from view-model to constructor of a

2019-06-05 14:24发布

问题:

I use caliburn micro and MEF in wpf and I have this problem.

I create shell-view-model:

public interface IShellViewModel
{
    void ShowLogOnView();
    void ShowMessengerView(PokecAccount account);
}

[Export(typeof(IShellViewModel))]
public class ShellViewModel : Conductor<IScreen>, IShellViewModel
{
    public ShellViewModel()
    {
        ShowLogOnView();
    }

    public void ShowLogOnView()
    {
        ActivateItem(IoC.Get<LogOnViewModel>());
    }

    public void ShowMessengerView(PokecAccount account)
    {
        //send to constructor of MessangerViewModel paramter typeof PokecAccount(own class)
        ActivateItem(IoC.Get<MessengerViewModel>(account));
    }
}

From view-model I create and show in new view-model

[Export]
public class LogOnViewModel : Screen, IDataErrorInfo, ILogOnViewModel
{


    [Import]
    private IShellViewModel _shellViewModel;

    [Import]
    private IPokecConnection _pokecConn;

    private PokecAccount _account;

    public void LogOn(string nick, string password)
    {
        _account = _pokecConn.LogOn(nick, password);
        if (_account != null)
        {
            //create new view-model and show it, problem is send parameter to construtor of MessengerViewModel
            _shellViewModel.ShowMessengerView(_account);
        }
    }
}

Problem is here

        //send to constructor of MessangerViewModel paramter typeof PokecAccount(own class)
        ActivateItem(IoC.Get<MessengerViewModel>(account));

New view-model

[Export]
public class MessengerViewModel : Screen, IMessengerViewModel
{
    private PokecAccount _account;

    public MessengerViewModel(PokecAccount account)
    {
        _account = account;
    }
}

Problem is here:

    //send to constructor of MessangerViewModel paramter typeof PokecAccount(own class)
    ActivateItem(IoC.Get<MessengerViewModel>(account));

Parameter IoC.Get() can be only string.

How solve this?

回答1:

I wouldn't use the IoC class in this context, as this is an example of the service locator anti-pattern, and isn't recommended. Rob mentions this in his Caliburn.Micro documentation. You can also read http://blog.ploeh.dk/2010/02/03/ServiceLocatorIsAnAntiPattern.aspx for a nice description of the anti-pattern.

Instead, I would use an abstract factory pattern, and pass (an abstraction of) a factory into your shell view model. This can have methods to create a new logon view model, and messenger view model. In the concrete implementation of this factory, you can instantiate these view models by hand, and just pass in the information they require.

I would also remove the reference to the shell view model from the logon view model. Instead, either use standard .NET events which the shell can subscribe to, or have a look at the event aggregator implemented in Caliburn.Micro (a sample is available on the codeplex site), which is an implementation of the mediator design pattern. This will ensure nice decoupling between your view models.