2013-07-23 23 views
10

Sto imparando Caliburn Micro e provo a utilizzare lo EventAggregator dal official site.Caliburn Micro Constructor Injection Failed

Tuttavia, ho ottenuto un'eccezione

"No costruttore senza parametri definiti per questo oggetto."

Il messaggio è chiaro ma l'esempio non include neanche un costruttore senza parametri. Se aggiungo uno, il costruttore con parametro non viene colpito e il IEventAggregator non viene ancora iniettato correttamente.

Ecco il mio editore VM dopo aver aggiunto il costruttore senza parametri (senza di essa, verrà generata un'eccezione):

public MainViewModel() { } 

    public MainViewModel(IEventAggregator ea) : this() 
    { 
     eventAggregator = ea; 
    } 

Ed ecco il programma di avvio automatico che sto usando:

public class AppBootstrapper : Bootstrapper<MainViewModel> 
{ 
    private readonly SimpleContainer container = new SimpleContainer(); 

    protected override void Configure() 
    { 
     container.Singleton<IEventAggregator, EventAggregator>(); 
    } 
} 

Ecco il esempio dalla CM:

// Creating the EventAggregator as a singleton. 
public class Bootstrapper : BootstrapperBase { 
    private readonly SimpleContainer _container = 
     new SimpleContainer(); 

    // ... Other Bootstrapper Config 

    protected override void Configure(){ 
     _container.Singleton<IEventAggregator, EventAggregator>(); 
    } 

    // ... Other Bootstrapper Config 
} 

// Acquiring the EventAggregator in a viewModel. 
public class FooViewModel { 
    private readonly IEventAggregator _eventAggregator; 

    public FooViewModel(IEventAggregator eventAggregator) { 
     _eventAggregator = eventAggregator; 
    } 
} 

ho controllato questo post (Inject EventAggregator into ViewModel with Caliburn Micro), ma semplicemente non ha detto nulla perché il CM non invoca il costruttore con l'iniezione.

Ho anche controllato la soluzione di esempio del CM ma utilizza MEF come soluzione DI.

Cosa mi manca?

+0

E 'stato un po' che non ho guardato Caliburn, ma sei sicuro che il vostro programma di avvio automatico è effettivamente iniziato, può ottenere le istanze, ecc? Dai un'occhiata a questo http://caliburnmicro.codeplex.com/SourceControl/latest#samples/Caliburn.Micro.HelloSimpleContainer/Caliburn.Micro.HelloSimpleContainer/Bootstrapper.cs esempio di contenitore semplice, non usa MEF o altro –

+0

@MaksimS. Configure() viene eseguito; Ho provato ad aggiungere Start() al costruttore bootstrapper ma non ho avuto fortuna. Inoltre, l'esempio non inserisce nulla nella VM. – ender

+0

Non hai nulla per testare il tuo codice al momento; tuttavia, è sufficiente dare un'occhiata al codice EventAggregator nell'ultima build e esso contiene _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ Per caso, usi EventAggregator da Prism o qualcos'altro invece di Caliburn? So che sembra sciocco, ma ancora :) –

risposta

8
// ... Other Bootstrapper Config 

È l'altra configurazione del bootstrapper che è importante.

L'opzione migliore è installare Caliburn.Micro tramite il pacchetto Caliburn.Micro.Start NuGet e dare un'occhiata al bootstrapper fornito che utilizza anche il SimpleContainer fornito da Caliburn.Micro.

Qui è in piena:

public class AppBootstrapper : BootstrapperBase 
{ 
    SimpleContainer container; 

    public AppBootstrapper() 
    { 
     Start(); 
    } 

    protected override void Configure() 
    { 
     container = new SimpleContainer(); 
     container.Singleton<IWindowManager, WindowManager>(); 
     container.Singleton<IEventAggregator, EventAggregator>(); 
     container.PerRequest<IShell, ShellViewModel>(); 
    } 

    protected override object GetInstance(Type service, string key) 
    { 
     var instance = container.GetInstance(service, key); 
     if (instance != null) 
      return instance; 
     throw new InvalidOperationException("Could not locate any instances."); 
    } 

    protected override IEnumerable<object> GetAllInstances(Type service) 
    { 
     return container.GetAllInstances(service); 
    } 

    protected override void BuildUp(object instance) 
    { 
     container.BuildUp(instance); 
    } 

    protected override void OnStartup(object sender, System.Windows.StartupEventArgs e) 
    { 
     DisplayRootViewFor<IShell>(); 
    } 
} 
+0

grazie, ci proverò. – ender

8

devdigital è corretta. Ha detto

è l'altra configurazione del bootstrapper che è importante.

Questo è completamente corretto.

Se avete intenzione di usare DI (che SimpleContainer fa per voi) quindi è necessario eseguire l'override le GetInstance(), GetAllInstances(), BuildUp() metodi nel vostro programma di avvio automatico, perché CM chiama questi metodi quando si vuole qualcosa dal contenitore.

Quello che sta accadendo nella vostra situazione è simile a questo:

  1. CM cerca di mostrare il vostro MainViewModel perché è stato specificato come parametro generico nel Bootstrapper.
  2. CM nota che il tuo MainViewModel ha un costruttore che accetta uno IEventAggregator.
  3. CM chiama GetInstance() per ottenere ciò che è registrato come IEventAggregator.
  4. CM rileva che non è stato eseguito l'override di GetInstance(), quindi tenta di creare un'istanza di MainViewModel utilizzando Activator.CreateInstance().
  5. Activator.CreateInstance() non sa come creare un IEventAggregator in modo da generare un'eccezione (quella che si ottiene).

Per risolvere tutto questo è necessario ignorare i metodi di cui ho parlato. Non è necessario installare Nuget Caliburn. Avvia il pacchetto (puoi utilizzarlo se non ti piace digitare e vuoi salvare alcuni tasti).

In sostanza la soluzione finale dovrebbe essere simile a questo:

public class Bootstrapper : Bootstrapper<MainViewModel> 
    { 

     private readonly SimpleContainer _container = new SimpleContainer(); 

     protected override void Configure() 
     { 
      _container.Instance<IWindowManager>(new WindowManager()); 
      _container.Singleton<IEventAggregator, EventAggregator>(); 
      _container.PerRequest<MainViewModel>(); 
     } 

     protected override object GetInstance(Type service, string key) 
     { 
      return _container.GetInstance(service, key); 
     } 

     protected override IEnumerable<object> GetAllInstances(Type service) 
     { 
      return _container.GetAllInstances(service); 
     } 

     protected override void BuildUp(object instance) 
     { 
      _container.BuildUp(instance); 
     } 

    } 
+1

Grande spiegazione, grazie. – Nestor