Domanda

public class StatisticsViewPresenter
{
    private IStatisticsView view;
    private Statistics statsModel;

    public StatisticsViewPresenter(IStatisticsView view, Statistics statsModel)
    {
        this.view = view;
        this.statsModel = statsModel;
    }
}

Non faccio uso di eventi (ma sono disposto a se può risolvere il mio problema), quindi le mie classi di visualizzazione simile a questa:

public class StatisticsForm : Form, IStatisticsView
{
    public StatisticsForm()
    {
        InitializeComponent();
    }

    [Inject]
    public StatisticsViewPresenter Presenter
    {
        private get;
        set;
    }
}

Con

kernel.Bind<StatisticsPresenter>().ToSelf().InSingletonScope();
kernel.Bind<IStatisticsView>().To<StatisticsForm>();
kernel.Get<IStatisticsView>();

si accumula il modulo, si accumula il presentatore, poi inietta il presentatore nella proprietà Presenter. Peachy di tutto. . (? A parte che il presentatore Singleton con ambito - qualche idea su un modo migliore per farlo che forse solo iniettare manualmente il presentatore in proprietà presentatore della vista all'interno del costruttore del presentatore: this.view.Presenter = questo)

Ma se mi rivolgo StatisticsForm in StatisticsUserControl e drag-drop sul mio MainForm, non è essere iniettato in MainForm da Ninject, è semplicemente di essere new'd dal progettista. Vedo tre soluzioni qui:

1) Non utilizzare controlli utente e basta usare una forma gigante che implementa queste viste multiple (eww);

2) Iniettare controlli utente nella mia forma e perdere il supporto del progettista;

3) La vostra soluzione! :)

È stato utile?

Soluzione

Questa è certamente una zona interessante di, dovrei dire, la ricerca. Abbiamo fatto noi stessi una soluzione in cui ospitiamo controlli utente in una forma generica.

La nostra forma generica non è indicato per l'uso con il Designer. Tramite il codice aggiungiamo il controllo utente scelto per il modulo in modo dinamico.

Per le altre strutture si dovrebbe guardare Prism / composito da la Patterns & Practices gruppo Microsoft. Ecco un articolo discutere le estensioni per WinForms.

Altri suggerimenti

Il mio approccio da utilizzare Ninject con forme, usercontrols e il progettista è:

  • Utilizzare fabbriche per creare le forme (anche per i controlli utente se si crea alcuni controlli dinamicamente)
  • per i controlli utente e le forme mantengono i costruttori senza parametri e l'iniezione di proprietà
  • strategia di attivazione al kernel che controllare se Ninject ha appena creato una maschera o un UserControl. Se questo è il caso, le itera strategia di attivazione oltre i controlli nel proprietà Controls del UserControl (o il modulo) e chiede Kernel.Inject (UserControl) per ogni UserControl. (Una strategia di attivazione è un codice ninject eseguito dopo aver iniettato un oggetto)

È possibile utilizzare il designer e hanno forme e usercontrols con dipendenze iniettato attraverso Ninject.

L'unico inconveniente è che si deve utilizzare l'iniezione di proprietà, invece di iniezione costruttore per i UserControls (e le forme)

namespace Majiic.Ninject
{
public class WindowsFormsStrategy : ActivationStrategy
{
    // Activate is called after Kernel.Inject
    //even for objects not created by Ninject
    //To avoid multiple "injections" in the same nested controls
    //we put this flag to false.
    private bool _activatingControls = false;
    public override void Activate(IContext context, InstanceReference reference)
    {
        reference.IfInstanceIs<UserControl>(uc =>
        {
            if (!_activatingControls)
            {
                Trace.TraceInformation("Activate. Injecting dependencies in User control of type {0}", uc.GetType());
                _activatingControls = true;
                context.Kernel.InjectDescendantOf(uc);
                _activatingControls = false;
            }
        });
        reference.IfInstanceIs<Form>(form =>
        {
            if (!_activatingControls)
            {
                Trace.TraceInformation("Activate. Injecting dependencies in Form of type {0}", form.GetType());
                _activatingControls = true;
                context.Kernel.InjectDescendantOf(form);
                _activatingControls = false;
            }
        });
    }


}
}

Crea il kernel e aggiungere la strategia di attivazione

var kernel=new StandardKernel(new CommonMajiicNinjectModule());
kernel.Components.Add<IActivationStrategy, WindowsFormsStrategy>();

estensioni del kernel per iterare su Descendents controlli

namespace Majiic.Ninject
{
static public class WinFormsInstanceProviderAux
{
    static public void InjectDescendantOf(this IKernel kernel, ContainerControl containerControl)
    {
        var childrenControls = containerControl.Controls.Cast<Control>();
        foreach (var control in childrenControls )
        {
            InjectUserControlsOf(kernel, control);
        }
    }

    static private void InjectUserControlsOf(this IKernel kernel, Control control)
    {
        //only user controls can have properties defined as n-inject-able
        if (control is UserControl)
        {
            Trace.TraceInformation("Injecting dependencies in User Control of type {0}", control.GetType());
            kernel.Inject(control);
        }
        //A non user control can have children that are user controls and should be n-injected
        var childrenControls = control.Controls.Cast<Control>();
        foreach (var childControl in childrenControls )
        {
            InjectUserControlsOf(kernel, childControl );
        }
    }
}
}

Di recente ho creato un po 'di UserControls riutilizzabili con la necessità di dipendenze da iniettare. Come il IoC Container non viene utilizzato per creare questi UserControls, ovviamente, non può iniettare automaticamente i Dipendenze.

La mia soluzione è una classe base per consentire almeno iniezione Proprietà. Costruttore di iniezione non è supportato, come un costruttore senza parametri viene utilizzato per creare tali istanze.

public class NinjectUserControl : UserControl
{

    // Generally this is considered to be a bad practice, 
    //however I didn't find any better way. If you do, please share :)
    public static IKernel Kernel { private get; set; } 

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        RequestActivation(Kernel);
    }

    protected virtual void RequestActivation(IKernel kernel)
    {
        kernel?.Inject(this);
    }
}

Per farlo funzionare è necessario impostare il kernel una volta. In genere questo è da qualche parte all'interno del vostro program.cs (WinForms) o App.xaml.cs (WPF)

IocKernel = new StandardKernel(); // typically a static member
NinjectUserControl.Kernel = IocKernel;
IocKernel.Load(new Module()); // loading modules
// .. Create MainForm or whatever

Per usare, è sufficiente ereditare NinjectUserControl e poi lasciare che il kernel Iniettare le dipendenze tramite iniezione Proprietà:

[Inject]
public IService Service { private get; set; }
  

Si prega di notare che tali dipendenze non sono accessibili all'interno del costruttore.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top