Sdílet prostřednictvím


Ioc (Inversion of control)

Běžným vzorem, který lze použít ke zvýšení modularity v základu kódu aplikace pomocí vzoru MVVM, je použít určitou formu inverze řízení. Jedním z nejběžnějších řešení je použití injektáže závislostí, která se skládá z vytvoření řady služeb, které jsou vloženy do back-endových tříd (tj. předány jako parametry konstruktorům modelu viewmodel) – to umožňuje kód, který tyto služby nepoužívá, nespoléhá na podrobnosti implementace těchto služeb a také usnadňuje prohození konkrétních implementací těchto služeb. Tento model také usnadňuje zpřístupnění funkcí specifických pro platformu pro back-endový kód tím, že je abstrahuje prostřednictvím služby, která se pak vloží tam, kde je to potřeba.

Sada MVVM Toolkit neposkytuje integrovaná rozhraní API, která usnadňují používání tohoto modelu, protože již existují vyhrazené knihovny speciálně pro tento balíček Microsoft.Extensions.DependencyInjection , který poskytuje plně funkční a výkonnou sadu rozhraní API di a funguje jako snadná instalace a použití IServiceProvider. Následující průvodce bude odkazovat na tuto knihovnu a poskytne řadu příkladů, jak ji integrovat do aplikací pomocí vzoru MVVM.

Rozhraní API platformy: Ioc

Konfigurace a řešení služeb

Prvním krokem je deklarování IServiceProvider instance a inicializace všech potřebných služeb, obvykle při spuštění. Například v UPW (ale podobné nastavení je možné použít i v jiných architekturách):

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

Services Zde je vlastnost inicializována při spuštění a všechny aplikační služby a viewmodely jsou registrovány. K dispozici je také nová Current vlastnost, která se dá použít pro snadný přístup k Services vlastnosti z jiných zobrazení v aplikaci. Například:

IFilesService filesService = App.Current.Services.GetService<IFilesService>();

// Use the files service here...

Klíčovým aspektem je, že každá služba může velmi dobře používat rozhraní API specifická pro platformu, ale protože jsou všechny abstrahovány prostřednictvím rozhraní, které náš kód používá, nemusíme se o ně starat, kdykoli pouze řešíme instanci a používáme ji k provádění operací.

Injektáž konstruktoru

Jednou z výkonných funkcí, která je k dispozici, je injektáž konstruktoru, což znamená, že poskytovatel služby DI dokáže automaticky vyřešit nepřímé závislosti mezi registrovanými službami při vytváření instancí požadovaného typu. Zvažte následující službu:

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

Tady máme FileLogger typ, který implementuje IFileLogger rozhraní a vyžaduje IFilesService a IConsoleService instance. Injektáž konstruktoru znamená, že poskytovatel služby DI automaticky shromáždí všechny potřebné služby, například takto:

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

Poskytovatel služby DI automaticky zkontroluje, jestli jsou zaregistrované všechny potřebné služby, pak je načte a vyvolá konstruktor pro registrovaný IFileLogger konkrétní typ, aby se instance vrátila.

A co modely viewmodels?

Poskytovatel služeb má v názvu "službu", ale ve skutečnosti se dá použít k překladu instancí jakékoli třídy, včetně modelů viewmodels! Stejné koncepty, které jsme vysvětlili výše, stále platí, včetně injektáže konstruktoru. Představte si, že jsme měli ContactsViewModel typ pomocí jeho konstruktoru IContactsService IPhoneService a instance. Mohli bychom mít metodu, ConfigureServices jako je tato:

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

A pak bychom v našem ContactsViewpřípadě přiřadili kontext dat následujícím způsobem:

public ContactsView()
{
    this.InitializeComponent();
    this.DataContext = App.Current.Services.GetService<ContactsViewModel>();
}

Další dokumenty

Další informace najdete Microsoft.Extensions.DependencyInjectiontady.

Příklady

  • Podívejte se na ukázkovou aplikaci (pro více architektur uživatelského rozhraní) a podívejte se na sadu nástrojů MVVM v akci.
  • Další příklady najdete také v testech jednotek.