3

I am very new to using dependency injection, and I am trying it out with Ninject in my WPF application. I was wondering how should I be passing parameters across classes.

For e.g.

public class ViewPersonViewModel : ViewModelBase
{
    private IDataAccessService _dataService;
    private IPerson _person;
    private string _remarks;

    // binded to textbox
    public string Remarks
    {
        get { return _remarks; }
        set {
            if (_remarks != value) {
                remarks = value;
                OnPropertyChanged("Remarks");
            }
        }   
    }

    public ViewPersonViewModel(
        IDataAccessService dataService, IPerson person)
    {
        _dataService= dataService;
        _person = person;
    }

    // binded to Button
    public void RetrieveStatus()
    {
        Remarks = _dataService.RetrieveRemarks(_person);
    }
}

In here, dataService is a fixed class, where I presumably can do

class Module : Ninject.Modules.NinjectModule 
{
    public override void Load() 
    {
        Bind<IDataAccessService>().To<DefaultDataAccessService>();
    }
}

But I will like to know how should I handle the person parameter, where it is set by the calling class.

I saw from Creating an instance using Ninject with additional parameters in the constructor that it is possible to pass additional parameters in the constructor.

However, I have a few concerns:

  1. Is using kernel.Get<MyClass>( With.Parameters.ConstructorArgument( "parameterName", parameterValue) ); an ideal way? Wouldn't it cause a lot of problems in debugging such as when you have typed your parameterName by mistake?

  2. Ruben also mentioned about using a more complicated way where Provider is involved. Is it applicable here? If it is, how can I use it?

Community
  • 1
  • 1
Wee
  • 278
  • 4
  • 16
  • Why do you have those services in your view model? Your view model should just contain data, not behavior. This is the root cause of your problem, since you are mixing data with behavior, which is a general cause of failure when using Dependency Injection. – Steven Jun 14 '12 at 10:12
  • I have intended this viewModel to utilise the DefaultDataAccessService to obtain the data (string remarks) to be displayed. If it shouldn't be here, where should I put it? – Wee Jun 14 '12 at 14:18
  • You can put in on your form / page class or even extract it to a service class that you load in your page. – Steven Jun 14 '12 at 14:32
  • But I'm trying to follow the mvvm pattern too, and there wouldn't be any codes in the view class. And I have already extracted it to DataAccessService class. I'm not sure what u are proposing. – Wee Jun 14 '12 at 15:18
  • If you don't have any code in the view class, why does it has dependencies? The `RetrieveStatus()` method looks like code to me. – Steven Jun 14 '12 at 17:26
  • @Steven, I am confused at what you mean. You have proposed me to move the code from my current viewmodel class to my form/page (view) class. As I am using bindings from the view to the viewmodel class, there is no code in the view class. The RetrieveStatus() method is in the viewModel class, not the view class. I will appreciate if you can elaborate on what you are trying to mean. Thanks. – Wee Jun 15 '12 at 04:23
  • I'm not an WPF expert, and I am hoping some of the DI experts with WPF experience can guide you how to model things in WPF. – Steven Jun 15 '12 at 17:31

2 Answers2

0

What you might consider doing is overloading the constructor like this:

public ViewPersonViewModel(IPerson person)
    this(DependencyResolver.GetInstance<IDataAccessService>(), person)
{
}

public ViewPersonViewModel(
    IDataAccessService dataService, IPerson person)
{
    _dataService= dataService;
    _person = person;
}

The major downside to this is that you can't request ViewPersonViewModel directly through your IoC.

Nathan
  • 1,080
  • 7
  • 16
0

Ninject 3 provided a convenient function that allows me to pass the parameters across classes. By creating an interface like

public interface IViewPersonViewModelFactory()
{
    IViewPersonViewModel CreateViewPersonViewModel([parameterType parameterName..]);
}

and adding the following to the Ninject module to be loaded:

public override void Load()
{
    Bind<IMainControllingViewModelFactory>().ToFactory();
    ... ... //other bindings
}

We can then obtain an instance of the ViewPersonViewModel class (for e.g. in the MainViewModel class)

 public class MainViewModel
 {
     private IViewPersonViewModel _viewModel;

     public MainViewModel(IViewPersonViewModelFactory viewModelFactory)
     {
         _viewModel = viewModelFactory.CreateViewPersonViewModel(parameters..);
     }
 }

Note that no concrete factory has to be created.

The wiki can be found at: https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface

Wee
  • 278
  • 4
  • 16