2010-04-30 17 views
5

Stiamo utilizzando Microsoft Unità e l'iniezione di dipendenza e costruttore, in modo che abbiamo parametrizzato per l'UserControl. Come iniettare questa dipendenza in usercontrol usando XAML?WPF UserControl con il costruttore parametrizzata

ho aggiunto l'UserControl in XAML come di seguito.

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

risposta

10

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.

+0

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

+0

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

+0

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. –

0

Sembra piuttosto facile. Perché non aggiungi semplicemente "un costruttore pubblico senza parametri" al tuo UserControl? Puoi scegliere di non usarlo direttamente nel tuo codice ma è ciò che il Designer sta cercando. Se si desidera assicurarsi che non venga mai chiamato nel codice, inserire a check for presence of Designer e generare un'eccezione se Designer non viene rilevato.

0

Funziona, ma le prestazioni sono molto male quando si utilizza griglie o schermi WPF complessi. Inherits = true implica che tutti gli elementi della GUI creati avranno la PropertyChangedCallback della proprietà associata chiamato subito dopo il costruttore, anche se questo elemento GUI specifica non ha bisogno di unità a tutti. E quando si hanno griglie, ogni volta che appare una nuova riga tutti gli elementi della GUI vengono creati al volo, con quella richiamata chiamata. questo stava uccidendo le prestazioni della nostra griglia, quindi abbiamo dovuto rimuovere UnityInjection fatto in questo modo.

Tuttavia, ci sono dei punti in cui abbiamo bisogno di UnityInjection in codebehind, e non abbiamo trovato una buona soluzione per questo problema, anche se stiamo usando MVVM. Alcuni controlli utente complessi sono progettati utilizzando MVVM, in cui ViewModel del controllo viene creato dal codebehind del controllo stesso, creato dallo XAML che sta utilizzando il controllo. In questo caso specifico il ViewModel del controllo non sa nulla (ancora) di Unity, ma abbiamo bisogno dell'iniezione di unità in esso, per accedere alle risorse esterne lì registrate.

Problemi correlati