Skip to content

Использование шаблона MVVM для заполнения элементами закрепления

Контрол DockManager позволяет использовать шаблон проектирования MVVM для заполнения контрола элементами закрепления (например, объектами DocumentPane и DockPane). При этой технике вы назначаете коллекцию элементов закрепления компоненту DockManager и указываете шаблон, используемый для отрисовки элементов закрепления.

Заполнение DockManager элементами из источника данных

Используйте свойство DockManager.ItemsSource для привязки DockManager к коллекции объектов, которые необходимо отобразить как элементы закрепления. Способ преобразования этих объектов в элементы закрепления задаётся свойством DockManager.ItemTemplate.

Чтобы указать шаблон для отрисовки содержимого элементов закрепления, созданных из коллекции DockManager.ItemsSource, используйте свойство DockManager.ItemContentTemplate.

Следующий пример из демо IDE Layout использует свойство DockManager.ItemsSource для привязки контрола к коллекции Documents, определённой в главной View Model. Элементы этой коллекции (объекты IdeLayoutDocumentViewModel) отображаются как объекты DocumentPane.

<mxd:DockManager Grid.Column="0" Grid.Row="1"
                 BorderThickness="0" 
                 ItemsSource="{Binding Documents}"
                 ItemContentTemplate="{views:IdeLayoutDocumentContentTemplate}">
    <mxd:DockManager.ItemTemplate>
        <DataTemplate DataType="vm:IdeLayoutDocumentViewModel">
            <mxd:DocumentPane Header="{Binding Header}"
                IsActive="{Binding IsActive}"
                CloseCommand="{Binding CloseCommand}"/>
        </DataTemplate>
    </mxd:DockManager.ItemTemplate>
    <mxd:DockGroup>
        <!-- ... -->
        <!-- Created DocumentPane objects are placed in the first DocumentGroup container. -->
        <mxd:DocumentGroup DockWidth="5*">
        </mxd:DocumentGroup>
    </mxd:DockGroup>
</mxd:DockManager>
public partial class IdeLayoutPageViewModel : PageViewModelBase
{
    public ObservableCollection<IdeLayoutDocumentViewModel> Documents { get; };
    //...
}

public partial class IdeLayoutDocumentViewModel : ObservableObject
{
    [ObservableProperty] private string header;
    [ObservableProperty] private string uri;
    [ObservableProperty] private bool isActive;
    [ObservableProperty] private ICommand closeCommand;
}

public class IdeLayoutDocumentContentTemplate : MarkupExtension, IDataTemplate
{
    //...
}

См. полный код этого примера в модуле IDE Layout Демо-приложения.

Note

Когда объекты DocumentPane создаются из коллекции DockManager.ItemsSource, они автоматически отображаются как вкладки в первом контейнере DocumentGroup. Убедитесь, что DockManager имеет хотя бы один контейнер DocumentGroup. Вы можете реализовать адаптер элементов (DockManager.ItemAdapter), чтобы размещать созданные элементы закрепления (например, объекты DocumentPane) в определённом контейнере закрепления. Для получения более подробной информации см. следующий раздел.

Создание различных типов элементов закрепления из источника данных

Вы можете захотеть привязать свойство DockManager.ItemsSource к коллекции объектов, которые должны отображаться как панели закрепления, документы, автоматически скрываемые панели и/или плавающие панели. Для выполнения этой задачи используйте следующий подход:

  1. Реализуйте селектор шаблонов, который создаёт определённые элементы закрепления из объектов в коллекции DockManager.ItemsSource.
  2. Добавьте контейнеры закрепления в компонент DockManager, которые должны размещать созданные элементы закрепления.
  3. Создайте адаптер элементов, который помещает созданные элементы закрепления в определённые контейнеры закрепления.

Пример

  1. Определите коллекцию Panes в главной View Model. Эта коллекция будет содержать следующие элементы:

  2. Объекты DockPaneViewModel - Эти объекты должны отображаться как панели закрепления (DockPane).

  3. Объекты DocumentPaneViewModel - Эти объекты должны отображаться как панели документов (DocumentPane).
namespace EremexAvaloniaApplication1;

public class MainViewModel : ObservableObject
{
    public ObservableCollection<PaneViewModelBase> Panes { get; } = new();
}

public partial class PaneViewModelBase : ObservableObject
{
    [ObservableProperty] private string? header;
}

public class DockPaneViewModel : PaneViewModelBase { }
public class DocumentPaneViewModel : PaneViewModelBase { }
  1. Инициализируйте коллекцию Panes примерами объектов.
namespace EremexAvaloniaApplication1;

public partial class MainWindow : MxWindow
{
    public MainWindow()
    {
        var viewModel = new MainViewModel();
        viewModel.Panes.AddRange(new PaneViewModelBase[]
        {
            new DockPaneViewModel() { Header = "Pane1" },
            new DockPaneViewModel() { Header = "Pane2" },
            new DockPaneViewModel() { Header = "Pane3" },
            new DocumentPaneViewModel() { Header = "Doc1" },
            new DocumentPaneViewModel() { Header = "Doc2" }
        });
        DataContext = viewModel;

        InitializeComponent();
    }
}
  1. Определите компонент DockManager в главном окне. Привяжите его к коллекции MainViewModel.Panes и создайте два контейнера закрепления:

  2. paneHost — Контейнер DockGroup, который должен отображать панели закрепления, созданные из объектов DockPaneViewModel.

  3. documentHost – Контейнер DocumentGroup, который должен отображать панели документов, созданные из объектов DocumentPaneViewModel.
<mx:MxWindow xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:mx="https://schemas.eremexcontrols.net/avalonia"
             xmlns:mxd="https://schemas.eremexcontrols.net/avalonia/docking"
             xmlns:local="clr-namespace:EremexAvaloniaApplication1"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="EremexAvaloniaApplication1.MainWindow"
             Icon="/Assets/EMXControls.ico"
             Title="EremexAvaloniaApplication1"
             x:DataType="local:MainViewModel">
    <mxd:DockManager ItemsSource="{Binding Panes}">
        <mxd:DockGroup>
            <mxd:DockGroup x:Name="paneHost" Orientation="Vertical"></mxd:DockGroup>
            <mxd:DocumentGroup x:Name="documentHost"></mxd:DocumentGroup>
        </mxd:DockGroup>
    </mxd:DockManager>
</mx:MxWindow>
  1. Реализуйте селектор шаблонов, который создаёт объекты DockPane из элементов DockPaneViewModel и объекты DocumentPane из элементов DocumentPaneViewModel. Назначьте этот селектор шаблонов свойству DockManager.ItemTemplate.
namespace EremexAvaloniaApplication1;

public class PaneTemplateSelector : MarkupExtension, IDataTemplate
{
    public IDataTemplate? DocumentTemplate { get; set; }
    public IDataTemplate? DockPaneTemplate { get; set; }
    public Control? Build(object? param)
    {
        if (param is DocumentPaneViewModel) return DocumentTemplate?.Build(param);
        return DockPaneTemplate?.Build(param);
    }

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

    public override object ProvideValue(IServiceProvider serviceProvider) => this;
}
<mxd:DockManager ItemsSource="{Binding Panes}">
    <mxd:DockManager.ItemTemplate>
        <local:PaneTemplateSelector>
            <local:PaneTemplateSelector.DocumentTemplate>
                <DataTemplate DataType="local:DocumentPaneViewModel">
                    <mxd:DocumentPane Header="{Binding Header}" />
                </DataTemplate>
            </local:PaneTemplateSelector.DocumentTemplate>
            <local:PaneTemplateSelector.DockPaneTemplate>
                <DataTemplate DataType="local:DockPaneViewModel">
                    <mxd:DockPane Header="{Binding Header}" />
                </DataTemplate>
            </local:PaneTemplateSelector.DockPaneTemplate>
        </local:PaneTemplateSelector>
    </mxd:DockManager.ItemTemplate>
    <mxd:DockGroup>
        <mxd:DockGroup x:Name="paneHost" Orientation="Vertical"></mxd:DockGroup>
        <mxd:DocumentGroup x:Name="documentHost"></mxd:DocumentGroup>
    </mxd:DockGroup>
</mxd:DockManager>
  1. Создайте адаптер элементов, который помещает созданные объекты DockPane и DocumentPane в соответствующие контейнеры закрепления.

Адаптер элементов - это класс, реализующий интерфейс IDockManagerItemAdapter. Метод IDockManagerItemAdapter.Adapt вызывается для каждого элемента закрепления, созданного из коллекции DockManager.ItemsSource. Этот метод должен разместить элемент закрепления в определённом контейнере закрепления.

Используйте свойство DockManager.ItemAdapter для указания адаптера элементов.

namespace EremexAvaloniaApplication1;

public class PaneAdapter : MarkupExtension, IDockManagerItemAdapter
{
    public void Adapt(DockManager dockManager, DockItemBase dockItem, object item)
    {
        var target = dockManager.FindItem<DockGroup>(dockItem is DocumentPane ? "documentHost" : "paneHost"); 
        target?.Add(dockItem);
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
}
<mxd:DockManager ItemsSource="{Binding Panes}" ItemAdapter="{local:PaneAdapter}">
<!-- ... -->
  1. Запустите приложение, чтобы увидеть компонент DockManager, заполненный элементами закрепления из коллекции Panes.

dockmanager-mvvm-itemadapter-example



* Эта страница была переведена с помощью нейросети Deepseek.