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
988 stars 143 forks source link

How to use StyletIoC Inject? #164

Closed FaustPipeDream closed 3 years ago

FaustPipeDream commented 3 years ago

I have a service named TerminalModelService and registere it in Bootstrapper.cs in method ConfigureIoC:

public class Bootstrapper : Bootstrapper<RootViewModel>{
    ...
    protected override void ConfigureIoC(IStyletIoCBuilder builder)
        {
            builder.Bind<TerminalModelService>().ToSelf();
        }
    ...
}

and user it in :

 public class TerminalControlViewModel : Screen
    {
        [Inject]
        TerminalModelService TerminalModelService { get; set; }
    ....
    public void DoConfirm()
        {
            TerminalModelService.SaveTerminalModel.dosomething();
       }
 }

But TerminalModelService not inject and return null,I think I use it wrong way, How to inject Service ? Is there any StyletIoC sample ?

canton7 commented 3 years ago

How are you instantiating TerminalControlViewModel?

On 2 November 2020 07:53:59 GMT, FaustPipeDream notifications@github.com wrote:

I have a service named TerminalModelService and registere it in Bootstrapper.cs in method ConfigureIoC:

public class Bootstrapper : Bootstrapper<RootViewModel>{
   ...
   protected override void ConfigureIoC(IStyletIoCBuilder builder)
       {
           builder.Bind<TerminalModelService>().ToSelf();
       }
   ...
}

and user it in :

public class TerminalControlViewModel : Screen
   {
       [Inject]
       TerminalModelService TerminalModelService { get; set; }
   ....
   public void DoConfirm()
       {
           TerminalModelService.SaveTerminalModel.dosomething();
      }
}

But TerminalModelService not inject and return null,I think I user it wrong way, How to inject Service ? Is there any StyletIoC sample ?

-- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: https://github.com/canton7/Stylet/issues/164

FaustPipeDream commented 3 years ago

How are you instantiating TerminalControlViewModel? On 2 November 2020 07:53:59 GMT, FaustPipeDream @.***> wrote: I have a service named TerminalModelService and registere it in Bootstrapper.cs in method ConfigureIoC: public class Bootstrapper : Bootstrapper<RootViewModel>{ ... protected override void ConfigureIoC(IStyletIoCBuilder builder) { builder.Bind<TerminalModelService>().ToSelf(); } ... } and user it in : public class TerminalControlViewModel : Screen { [Inject] TerminalModelService TerminalModelService { get; set; } .... public void DoConfirm() { TerminalModelService.SaveTerminalModel.dosomething(); } } But TerminalModelService not inject and return null,I think I user it wrong way, How to inject Service ? Is there any StyletIoC sample ? -- You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHub: #164

I instantiated TerminalControlViewModel in RootViewModel by a command

public class RootViewModel : Conductor<IScreen>.Collection.OneActive
{
    ...
    public void DoShowTerminalControl()
            {
                TerminalControlViewModel TerminalControlViewModel = new TerminalControlViewModel();
                WindowManager.ShowWindow(TerminalControlViewModel);
            }
}

and bind it to a button:

<Button Header="new Terminal" Command="{s:Action DoShowTerminalControl}"/>
canton7 commented 3 years ago

IoC containers aren't magic -- there's no way for it to insert itself into your code and populate properties on TerminalControlViewModel after you instantiate it.

The normal pattern is to let the IoC container create TerminalControlViewModel as well:

public class RootViewModel : Conductor<IScreen>.Collection.OneActive
{
    private readonly Func<TerminalControlViewModel> factory;

    public RootViewMode(Func<TerminalControlViewModel> factory) => this.factory = factory;
    ...
    public void DoShowTerminalControl()
    {
        TerminalControlViewModel TerminalControlViewModel = factory();
        WindowManager.ShowWindow(TerminalControlViewModel);
    }
}

You can also use IContainer.BuildUp, but that's less common.

FaustPipeDream commented 3 years ago

a Thank you,It works, So the normal pattern to instantiate a viewModel is getting it by Func.I see.

canton7 commented 3 years ago

That's the case where you need to be able to create multiple instances of it. If you just need 1 instance, you can do:

public class RootViewModel : Conductor<IScreen>.Collection.OneActive
{
    private readonly TerminalControlViewModel terminalControlVm;

    public RootViewMode(TerminalControlViewModel terminalControlVm) => this.terminalControlVm= terminalControlVm;
    ...
    public void DoShowTerminalControl()
    {
        WindowManager.ShowWindow(terminalControlVm);
    }
}

This is the case in almost every IoC container

FaustPipeDream commented 3 years ago

I’m sorry but i have another problem,In TerminalViewModel ,there is a BindableCollection<TerminalTreeNode>TerminalTreeNodes,and I want to share it with TerminalControlViewModel,so that I can change the TerminalTreeNodes in TerminalControlViewModel. Usually,it can be realized by share one TerminalTreeNodes instance like

public class TerminalControlViewModel : Screen
    {
        public BindableCollection<TerminalTreeNode> TerminalTreeNodes { get; set; } = new BindableCollection<TerminalTreeNode>();
        public TerminalControlViewModel(BindableCollection<TerminalTreeNode> terminalTreeNodes)
        {
            TerminalTreeNodes = terminalTreeNodes;
       }
    }
public class TerminalViewModel : Screen
    {
        public BindableCollection<TerminalTreeNode> TerminalTreeNodes { get; set; } = new BindableCollection<TerminalTreeNode>();
       public TerminalViewModel()
           {
                    TerminalTreeNodes.addsomething();
           }
    }
public class RootViewModel : Conductor<IScreen>.Collection.OneActive
{
    private readonly Func<BindableCollection<TerminalTreeNode>,TerminalControlViewModel> Factory;
    private TerminalViewModel TerminalViewModel { get; set; }
     .....
    public RootViewMode(TerminalViewModel terminalViewModel,Func<BindableCollection<TerminalTreeNode>,TerminalControlViewModel> factory)
        {
              TerminalViewModel = terminalViewModel;
              Factory = factory;
        }
    ...
    public void DoShowTerminalControl()
    {
        TerminalControlViewModel TerminalControlViewModel = factory(TerminalViewModel.TerminalTreeNodes);
        WindowManager.ShowWindow(TerminalControlViewModel);
    }
}

But it doesn't work,and I found /issues/153 ,StyletIoC can't create factories which take arbitrary parameters. So how one viewModel sharing one TerminalTreeNodes with another? Should I use other IOC Container?

canton7 commented 3 years ago

You can use another ioc container which does support auto-generating factories which take arbitrary parameters, or you can write your own factory class. I tend to write my own factory class.