canton7 / Stylet

A very lightweight but powerful ViewModel-First MVVM framework for WPF for .NET Framework and .NET Core, inspired by Caliburn.Micro.
MIT License
994 stars 143 forks source link

how to create viewmodel with param #153

Closed ytianxia6 closed 3 years ago

ytianxia6 commented 4 years ago

I use a viewmodel like

public class RootViewModel(Func<NextViewModel> func, IWindowManager wndManager>
{
   public void ShowNext()
  {
    wndManager.ShowWindow(func());
  }
}

It works well. But if I want to pass a param to the NextViewModel, It cannot work.

public class RootViewModel(Func<int, NextViewModel> func, IWindowManager wndManager>
{
   public void ShowNext(int i)
  {
    wndManager.ShowWindow(func(i));
  }
}

It give me a Unable to find a constructor for type RootViewModel which we can call: error. How can I pass the param to the viewmodel?

haven1433 commented 4 years ago

You can pass in a custom factory interface instead of a func. Stylet can create an instance for you. Since you want custom parameters, you'll want to create an implimentation and then bind it manually.

ytianxia6 commented 4 years ago

I use custom factory instead, but if I pass a param not string, it throw error:

Can only implement methods with zero arguments, or a single string argument

the code:

    public interface IQueryViewModelFactory
    {
        QueryViewModel CreateQueryViewModel(JiraQuery query);
    }

    builder.Bind<IQueryViewModelFactory>().ToAbstractFactory();

if I implement the factory, the inject is null:

    public interface IQueryViewModelFactory
    {
        QueryViewModel CreateQueryViewModel(JiraQuery query);
    }
    public class QueryViewModelFactory : IQueryViewModelFactory
    {

        public QueryViewModel CreateQueryViewModel(JiraQuery query)
        {
            return new QueryViewModel(query);
        }
    }

// bind
builder.Bind<IQueryViewModelFactory>().To<QueryViewModelFactory>();

// first viewmodel
public RootViewModel(IQueryViewModelFactory queryViewModelFactory, IWindowManager windowManager)
{
  ...
}

// show second viewmodel
_windowManager.ShowWindow(_queryViewModelFactory.CreateQueryViewModel(query));

// in the second viewmodel, the inject is null

    public class QueryViewModel : Screen
{
    public QueryViewModel(JiraQuery query)
    {
        ...
    }

        [Inject]
        public IOtherInject  OtherInject{ get; set; }  // this is null

}
ytianxia6 commented 4 years ago

I'm newer to Stylet, but I think i will switch to other mvvm framework. sine there are so few resources and documents!

canton7 commented 4 years ago

The ioc container provided with Stylet isn't powerful enough to create factories which take arbitrary parameters.

One option is to switch to another ioc container -- there's info on this in the docs.

Another option is to write your own factory:

public class NextViewModelFactory
{
    public QueryViewModel CreateQueryViewModel(JiraQuery query)
    {
        return new QueryViewModel(....);
    }
}

public class RootViewModel(NextViewModelFactory factory, IWindowManager wndManager>
{
   public void ShowNext()
  {
    wndManager.ShowWindow(factory.CreateQueryViewModel(...));
  }
}

Another option is to just instantiate the ViewModel yourself:

public class RootViewModel(NextViewModelFactory factory, IWindowManager wndManager>
{
   public void ShowNext()
  {
    wndManager.ShowWindow(new QueryViewModel(...));
  }
}

This isn't really an issue with Stylet - it's a question about dependency injection and ioc containers. You don't have to use dependency injection, and you don't have to use Stylet's (simple) ioc container.

canton7 commented 3 years ago

Closing as no response