Документация по Avalonia UI
< Все темы
Печать

Поиск представлений

Подожди, отмотай на секунду назад. Внимательный читатель заметит, что в последнем разделе происходит что-то странное.
Views/MainWindow.axaml

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Class="Todo.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Width="200" Height="300"
        Title="Avalonia Todo"
        Content="{Binding List}">
</Window>

Мы привязали свойство Window.Content к свойству MainWindowViewModel.List, которое является экземпляром TodoListViewModel, но в окне отображается TodoListView! Что тут происходит? Как отображается представление, когда содержимое окна является моделью представления?

Ответ можно найти в файле ViewLocator.cs, добавленном шаблоном:
ViewLocator.cs

using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Todo.ViewModels;

namespace Todo
{
    public class ViewLocator : IDataTemplate
    {
        public bool SupportsRecycling => false;

        public IControl Build(object data)
        {
            var name = data.GetType().FullName.Replace("ViewModel", "View");
            var type = Type.GetType(name);

            if (type != null)
            {
                return (Control)Activator.CreateInstance(type);
            }
            else
            {
                return new TextBlock { Text = "Not Found: " + name };
            }
        }

        public bool Match(object data)
        {
            return data is ViewModelBase;
        }
    }
}

ViewLocator определяет шаблон данных, который преобразует модели представлений в представления. Он определяет два метода:

  • Match(object data) просматривает данные, и если данные наследуются от ViewModelBase, он возвращает true, указывая на то, что следует вызывать Build.
  • Build(object data) принимает полное имя типа данных и заменяет строку "ViewModel" строкой "View". Затем он пытается получить тип, соответствующий этому имени. Если соответствующий тип найден, он создает экземпляр типа и возвращает его.

Экземпляр ViewLocator присутствует в Application.DataTemplates:

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Todo"
             x:Class="Todo.App">
    <Application.DataTemplates>
        <local:ViewLocator/>
    </Application.DataTemplates>

    <Application.Styles>
        <StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml"/>
        <StyleInclude Source="avares://Avalonia.Themes.Default/Accents/BaseLight.xaml"/>
    </Application.Styles>
</Application>

Когда для экземпляра ContentControl (например, Window) для свойства Content задано значение, не являющееся элементом управления, он ищет в дереве элементов управления шаблон DataTemplate, соответствующий данным содержимого. Если никакой другой DataTemplate не соответствует данным, он в конечном итоге достигнет ViewLocator в шаблонах данных приложения, который сделает свое дело и вернет экземпляр соответствующего представления.

ViewLocator включен в исходный код проекта, а не является компонентом самой Avalonia, поскольку механизм связывания модели представления с представлением может зависеть от приложения; например, можно реализовать его с помощью инфраструктуры DI. ViewLocator можно рассматривать как реализацию парадигмы соглашения по конфигурации.

Оглавление