Pregunta

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

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

No uso eventos (pero estoy dispuesto a si puede resolver mi problema), por lo que mis clases de visión se ven así:

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>();

Aumenta el formulario, construye el presentador, luego inyecta al presentador en la propiedad del presentador. Todo es durazno. (Excepto por ese presentador con escollar singleton, ¿cualquier pensamiento sobre una mejor manera de hacerlo? Quizás inyecte manualmente al presentador en la propiedad del presentador de la vista dentro del constructor del presentador: this.view.presenter = this).

Pero si convierto la formación de estadísticas en estadística de UCONTROL y la arrastre a mi forma principal, no está siendo inyectado en Mainform por Ninject, simplemente el diseñador es simplemente nuevo. Veo tres soluciones aquí:

1) No use UserControls y simplemente use una forma gigante que implementa estas múltiples vistas (EWW);

2) inyectar UserControls en mi forma y perder el soporte de diseñador;

3) ¡Tu solución! :)

¿Fue útil?

Solución

Esta es ciertamente un área interesante de, si digo, investigar. Nos hemos hecho una solución en la que organizamos controles de usuario en forma genérica.

Nuestra forma genérica no está destinada a su uso con el diseñador. A través del código, agregamos el control de usuario elegido al formulario dinámicamente.

Para otros marcos debes mirar Prisma/compuesto Del grupo de patrones y prácticas de Microsoft. Aquí hay un artículo Discutir extensiones para WinForms.

Otros consejos

Mi enfoque para usar Ninject con formularios, UserControls y el diseñador es:

  • Use fábricas para crear los formularios (también para UserControls si crea algunos controles dinámicamente)
  • Para los userControls y los formularios mantienen a los constructores sin parámetros y usan la inyección de propiedades
  • Agregar un Estrategia de activación al núcleo que verifique si Ninject acaba de crear un formulario o un UserControl. Si ese es el caso, la estrategia de activación itera sobre los controles en la propiedad de controles del UserControl (o el formulario) y llama a Kernel.inject (UserControl) para cada UserControl. (Una estrategia de activación es que se ejecuta algún código de código después de haber inyectado un objeto)

Puede usar el diseñador y tener formularios y UserControls con dependencias inyectadas a través de Ninject.

El único inconveniente es que tiene que usar la inyección de propiedad en lugar de la inyección de constructor para los usercontroles (y los formularios)

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 el núcleo y agregue la estrategia de activación

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

extensiones de núcleo para iterar sobre los controles de los descendientes

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 );
        }
    }
}
}

Recientemente creé algunos reutilizables UserControls con la necesidad de dependencias para inyectar. Como el IoC Container no se usa para crear esos UserControlS, obviamente no puede inyectar automáticamente las dependencias.

Mi solución es una clase base para permitir al menos la inyección de propiedad. La inyección del constructor no es compatible, ya que se utiliza un constructor sin parámetros para crear esas instancias.

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);
    }
}

Para que funcione, debe establecer el núcleo una vez. Por lo general, este está en algún lugar dentro de tu 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

Para usar, simplemente heredar NinjectUserControl y luego deje que el núcleo inyecte sus dependencias a través de la inyección de propiedad:

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

Tenga en cuenta que esas dependencias no son accesibles dentro del constructor.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top