Dependency Injection non implica costruttori con parametri. Infatti, se si guardano gli esempi forniti con Unity, la maggior parte dell'iniezione delle dipendenze viene eseguita per proprietà con l'attributo [Dependency].
Unità funziona molto bene con XAML, ma solo se non si utilizza costruttori con parametri. Converti il tuo UserControl per prendere le sue dipendenze usando le proprietà con l'attributo [Dependency], e puoi facilmente usare XAML.
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));
...
}
Nota che un [Dipendenza] proprietà può essere dichiarata sia come DependencyProperty o come una proprietà CLR pianura, come indicato sopra. Sembra una nomenclatura confusa, ma in pratica è molto semplice.
Per specificare l'UnityContainer in XAML e ottenere la configurazione automatica, basta creare una proprietà associata ereditato "UnityHelper.Container" il cui PropertyChangedCallback chiama semplicemente l'accumulo sul contenitore specificato e passa nel tipo di oggetto e l'oggetto:
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);
}
}
});
}
Ora è possibile assegnare un'UnityContainer alla finestra principale e l'intera applicazione verrà utilizzato, per esempio si potrebbe farlo nel costruttore della finestra come segue:
UnityHelper.SetContainer(this, new UnityContainer() ...);
Oppure è possibile assegnare il contenitore di unità utilizzando XAML a qualsiasi livello desiderato dell'albero:
<UserControl ...
my:UnityHelper.Container="{DynamicResource MainUnityContainer}" />
Detto questo, penso che sarete troverete che avanzata dei dati di WPF caratteristiche e dizionari risorse vincolanti insieme eliminano il 98% dei motivi per cui un la persona potrebbe voler usare Unity in primo luogo. Potresti trovarlo meglio a lungo andare ad allontanarti da Unity e andare con MVVM semplice. Per lo meno vorrei provare MVVM puro su un'applicazione di test per vedere come funziona prima di sviluppare molto codice affidandosi a Unity per l'iniezione delle dipendenze.
funziona, ma quando premo il pulsante di scheda da uno della casella di testo viene generata un'eccezione Risoluzione della dipendenza non è riuscita, type = "System.Windows.Input.KeyboardNavigation + FocusVisualAdorner", name = "". Il messaggio di eccezione è: L'attuale operazione di compilazione (chiave di build chiave di build [System.Windows.Input.KeyboardNavigation + FocusVisualAdorner, null]) non riuscita: impossibile caricare il tipo 'System.Windows.Input.KeyboardNavigation' dall'assembly 'PresentationFramework, Version = 3.0 .0.0, Culture = neutral, PublicKeyToken = 31bf3856ad364e35 '. (Strategia tipo BuildPlanStrategy, indice 5) – Miral
Questa risposta mi ha aiutato moltissimo. Vorrei poter dare più di +1. Ho aggiunto questa discussione a "I miei preferiti", ma solo crediti al tizio che ha posto la domanda originale. Quindi grazie! – Tormod
Se crei un'interfaccia (ad esempio chiamata IUnityElement) che applichi a tutti i tuoi UserControls o Controlli su cui devi eseguire l'unità, allora nella riga 'if (container! = Null)' puoi controllare se il parametro obj è di quell'interfaccia per esempio 'if (container! = null && obj is IUnityInject)'. Questo elimina l'errore di cui sopra Miral ha commentato (ne ho avuto uno simile da un oggetto diverso e la risposta del problema di prestazioni ZeePrime, dato che BuildUp è eseguito solo su FrameworkElements a cui è necessario. –