Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Un modello comune che può essere usato per aumentare la modularità nella codebase di un'applicazione usando il modello MVVM consiste nell'usare una forma di inversione del controllo. Una delle soluzioni più comuni in particolare consiste nell'usare l'inserimento delle dipendenze, che consiste nella creazione di un certo numero di servizi inseriti in classi back-end (ad esempio, passate come parametri ai costruttori del modello di visualizzazione), che consente al codice di usare questi servizi di non basarsi sui dettagli di implementazione di questi servizi e semplifica anche lo scambio delle implementazioni concrete di questi servizi. Questo modello semplifica anche la disponibilità di funzionalità specifiche della piattaforma per il codice back-end, astraendole tramite un servizio che viene quindi inserito dove necessario.
Il toolkit MVVM non fornisce API integrate per facilitare l'uso di questo modello, poiché esistono già librerie dedicate specifiche a questo scopo, come il pacchetto Microsoft.Extensions.DependencyInjection, che fornisce un set di API DI completo e potente e funge da IServiceProvider facile da configurare e usare. La guida seguente farà riferimento a questa libreria e fornirà una serie di esempi di come integrarlo nelle applicazioni usando il modello MVVM.
API della piattaforma:
Ioc
Configurare e risolvere i servizi
Il primo passaggio consiste nel dichiarare un'istanza IServiceProvider e inizializzare tutti i servizi necessari, in genere all'avvio. Ad esempio, in UWP (ma una configurazione simile può essere usata anche in altri framework):
public sealed partial class App : Application
{
public App()
{
Services = ConfigureServices();
this.InitializeComponent();
}
/// <summary>
/// Gets the current <see cref="App"/> instance in use
/// </summary>
public new static App Current => (App)Application.Current;
/// <summary>
/// Gets the <see cref="IServiceProvider"/> instance to resolve application services.
/// </summary>
public IServiceProvider Services { get; }
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<IFilesService, FilesService>();
services.AddSingleton<ISettingsService, SettingsService>();
services.AddSingleton<IClipboardService, ClipboardService>();
services.AddSingleton<IShareService, ShareService>();
services.AddSingleton<IEmailService, EmailService>();
return services.BuildServiceProvider();
}
}
In questo caso la Services proprietà viene inizializzata all'avvio e vengono registrati tutti i servizi dell'applicazione e i modelli di visualizzazione. È anche disponibile una nuova Current proprietà che può essere usata per accedere facilmente alla Services proprietà da altre visualizzazioni nell'applicazione. Ad esempio:
IFilesService filesService = App.Current.Services.GetService<IFilesService>();
// Use the files service here...
L'aspetto chiave qui è che ogni servizio potrebbe benissimo usare API specifiche della piattaforma, ma poiché queste vengono tutte astratte tramite l'interfaccia utilizzata dal nostro codice, non dobbiamo preoccuparcene ogni volta che ci limitiamo a risolvere un'istanza e a usarla per eseguire operazioni.
Iniezione tramite costruttore
Una funzionalità particolarmente potente disponibile è l'iniezione tramite costruttore, il che significa che il provider di servizi DI è in grado di risolvere automaticamente le dipendenze indirette tra i servizi registrati quando crea istanze del tipo richiesto. Si consideri il servizio seguente:
public class FileLogger : IFileLogger
{
private readonly IFilesService FileService;
private readonly IConsoleService ConsoleService;
public FileLogger(
IFilesService fileService,
IConsoleService consoleService)
{
FileService = fileService;
ConsoleService = consoleService;
}
// Methods for the IFileLogger interface here...
}
Qui abbiamo un tipo FileLogger che implementa l'interfaccia IFileLogger e richiede istanze di IFilesService e IConsoleService. L'iniezione tramite costruttore significa che il provider di servizi DI recupererà automaticamente tutti i servizi necessari, come segue:
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
services.AddSingleton<IFilesService, FilesService>();
services.AddSingleton<IConsoleService, ConsoleService>();
services.AddSingleton<IFileLogger, FileLogger>();
return services.BuildServiceProvider();
}
// Retrieve a logger service with constructor injection
IFileLogger fileLogger = App.Current.Services.GetService<IFileLogger>();
Il provider di servizi DI verificherà automaticamente se tutti i servizi necessari sono registrati, quindi li recupererà e invocherà il costruttore per il tipo concreto registrato IFileLogger, per ottenere l'istanza da restituire.
Che ne dici dei modelli di visualizzazione?
Un provider di servizi ha "servizio" nel nome, ma può effettivamente essere usato per risolvere le istanze di qualsiasi classe, inclusi i modelli di visualizzazione. Gli stessi concetti illustrati in precedenza continuano a valere, inclusa l'iniezione tramite costruttore. Immaginiamo di avere un tipo ContactsViewModel, che usa un'istanza IContactsService e un'istanza IPhoneService tramite il suo costruttore. È possibile avere un ConfigureServices metodo simile al seguente:
/// <summary>
/// Configures the services for the application.
/// </summary>
private static IServiceProvider ConfigureServices()
{
var services = new ServiceCollection();
// Services
services.AddSingleton<IContactsService, ContactsService>();
services.AddSingleton<IPhoneService, PhoneService>();
// Viewmodels
services.AddTransient<ContactsViewModel>();
return services.BuildServiceProvider();
}
E poi, nel nostro ContactsView, assegneremmo il contesto dei dati come segue:
public ContactsView()
{
this.InitializeComponent();
this.DataContext = App.Current.Services.GetService<ContactsViewModel>();
}
Altri documenti
Per altre info su Microsoft.Extensions.DependencyInjection, vedere qui.
Esempi
- Scopri l'app di esempio (per diversi framework dell'interfaccia utente) per vedere il MVVM Toolkit in azione.
- È anche possibile trovare altri esempi negli unit test.