2010-04-30 26 views
5

Estamos usando Microsoft Unity y la inyección de dependencia, por lo que tenemos el constructor parametrizado para el control de usuarios. ¿Cómo inyectar esta dependencia en usercontrol usando XAML?Wpf usercontrol con constructor con parámetros

He agregado el control de usuario en XAML como a continuación.

xmlns:usrRefundArrivalProcessor="Ttl.Refunds.Wpf.Dashboad.Application.Usercontrols;assembly=Ttl.Refunds.Wpf.Dashboad.Application" 

Respuesta

10

La inyección de dependencias no implica constructores parametrizados. De hecho, si observa las muestras que vienen con Unity, la mayor parte de la inyección de dependencia se realiza por propiedades con el atributo [Dependency].

Unity funciona muy bien con XAML, pero solo si no utiliza constructores parametrizados. Convierta su UserControl para tomar sus dependencias usando propiedades con el atributo [Dependency], y puede usar XAML fácilmente.

public class MyUserControl : UserControl 
{ 
    [Dependency] 
    public ISomething Something { get; set; } 

    [Dependency] 
    public IWhatever Whatever { get { return (IWhatever)GetValue(WhateverProperty); } set { SetValue(WhateverProperty, value); } 
    public readonly DependencyProperty WhateverProperty = DependencyProperty.Register("Whatever", typeof(IWhatever), typeof(MyUserControl)); 

    ... 
} 

Tenga en cuenta que una [Dependencia] propiedad puede ser declarado ya sea como una propiedad de dependencia o como una propiedad CLR llano, como se muestra arriba. Esto suena como una nomenclatura confusa, pero en la práctica es muy simple.

Para especificar el UnityContainer en XAML y obtener la configuración automática, basta con crear una propiedad adjunta heredada "UnityHelper.Container" cuya PropertyChangedCallback simplemente llama a la acumulación en el contenedor especificado y pasa en el tipo de objeto y el objeto:

public class UnityHelper 
{ 
    public static IUnityContainer GetContainer(DependencyObject obj) { return (IUnityContainer)obj.GetValue(ContainerProperty); } 
    public static void SetContainer(DependencyObject obj, IUnityContainer value) { obj.SetValue(ContainerProperty, value); } 
    public static readonly DependencyProperty ContainerProperty = DependencyProperty.RegisterAttached("Container", typeof(IUnityContainer), typeof(UnityHelper), new FrameworkPropertyMetadata 
    { 
    Inherits = true, 
    PropertyChangedCallback = (obj, e) => 
    { 
     var container = e.NewValue as IUnityContainer; 
     if(container!=null) 
     { 
     var element = obj as FrameworkElement; 
     container.BuildUp(obj.GetType(), obj, element==null ? null : element.Name); 
     } 
    } 
    }); 
} 

Ahora se puede asignar un UnityContainer a la ventana de su raíz y toda su aplicación va a usar, por ejemplo, usted podría hacerlo en el constructor de la ventana de la siguiente manera:

UnityHelper.SetContainer(this, new UnityContainer() ...); 

O puede asignar el contenedor de la unidad usando XAML en cualquier nivel deseado del árbol:

<UserControl ... 
    my:UnityHelper.Container="{DynamicResource MainUnityContainer}" /> 

Habiendo dicho todo esto, pienso que usted encontrará que las características y diccionarios de recursos de enlace de datos avanzadas de WPF juntos eliminan el 98% de las razones por las que una Es posible que la persona quiera usar Unity en primer lugar. Puede que a la larga sea mejor alejarse de Unity e ir con MVVM simple. Por lo menos, probaría MVVM puro en una aplicación de prueba para ver cómo funciona antes de desarrollar mucho código confiando en Unity para la inyección de dependencia.

+0

funciona, pero cuando pulso el botón de pestaña de uno de los cuadro de texto que arroja una excepción Resolución de la dependencia fracasó, type = "+ System.Windows.Input.KeyboardNavigation FocusVisualAdorner", name = "". El mensaje de excepción es: La operación de compilación actual (clave de compilación clave Build [System.Windows.Input.KeyboardNavigation + FocusVisualAdorner, null]) falló: no se pudo cargar el tipo 'System.Windows.Input.KeyboardNavigation' desde el ensamblado 'PresentationFramework, Version = 3.0 .0.0, Cultura = neutral, PublicKeyToken = 31bf3856ad364e35 '. (Tipo de estrategia BuildPlanStrategy, índice 5) – Miral

+0

Esta respuesta me ayudó muchísimo. Ojalá pudiera dar más de +1. He agregado este hilo a "Mis favoritos", pero eso solo acredita al tipo que hizo la pregunta original. ¡Así que gracias! – Tormod

+0

Si crea una interfaz (digamos llamada IUnityElement) que aplique a todos sus UserControls o Controls, necesita ejecutar la unidad en la línea 'if (container! = Null)', puede verificar si el parámetro obj es de esa interfaz p.ej 'if (contenedor! = nulo && obj es IUnityInject)'. Esto elimina el error que Miral comentó anteriormente (obtuve uno similar de un objeto diferente y el problema de rendimiento de la respuesta de ZeePrime, ya que BuildUp solo se ejecuta en FrameworkElements que lo necesite). –

0

Parece bastante fácil. ¿Por qué no simplemente agrega "un constructor público sin parámetros" a su UserControl? Puede elegir no usarlo en su código directamente, pero eso es lo que el Diseñador está buscando. Si desea asegurarse de que nunca se invoca en el código, ingrese a check for presence of Designer y genere una excepción si no se detecta el Diseñador.

0

Funciona, pero el rendimiento es bastante malo cuando utiliza cuadrículas o pantallas WPF complejas. Hereda = verdadero implica que todos los elementos de GUI creados tendrán el PropertyChangedCallback de la propiedad adjunta llamada justo después del constructor, incluso si ese elemento GUI específico no necesita Unity en absoluto. Y cuando tiene cuadrículas, cada vez que aparece una nueva fila, todos los elementos de la GUI se crean sobre la marcha, con esa devolución de llamada llamada. esto estaba matando el rendimiento de nuestra grilla, por lo que tuvimos que eliminar UnityInjection hecho de esta manera.

Sin embargo, hay lugares donde necesitamos UnityInjection en código subyacente, y no hemos encontrado una buena solución para este problema, incluso si estamos usando MVVM. Algún control de usuario complejo está diseñado utilizando MVVM, donde el modelo de vista del control se crea mediante el código detrás del control en sí, creado por el XAML que está utilizando el control. En este caso específico, el ViewModel del control no sabe nada (todavía) sobre Unity, pero NECESITAMOS Inyección Unitaria en él, para acceder a los recursos externos allí registrados.

Cuestiones relacionadas