Доработан Docking

This commit is contained in:
2026-01-27 05:17:35 +03:00
parent 33abd94f6e
commit 584df249f6
99 changed files with 2270 additions and 12792 deletions

View File

@@ -8,11 +8,43 @@ using System.Threading.Tasks;
namespace Lattice.UI.Docking.WinUI.Services;
/// <summary>
/// Реализация UI-сервиса для WinUI.
/// Реализация UI-сервиса для платформы WinUI.
/// Инкапсулирует платформенно-зависимые операции, такие как создание окон,
/// показ диалогов и синхронизация с UI-потоком.
/// </summary>
public sealed class WinUIDockUIService : DockUIServiceBase
/// <remarks>
/// <para>
/// <see cref="WinUIDockUIService"/> предоставляет конкретные реализации методов
/// <see cref="IDockUIService"/> для платформы WinUI. Это позволяет основной
/// бизнес-логике док-системы оставаться независимой от конкретной UI-платформы.
/// </para>
/// <para>
/// Сервис использует API WinUI для создания окон, показа ContentDialog и
/// управления диспетчером потока пользовательского интерфейса.
/// </para>
/// </remarks>
public sealed class WinUIDockUIService : DockUIServiceBase, IDockUIService
{
/// <inheritdoc/>
/// <summary>
/// Создает главное окно приложения для размещения док-хоста.
/// </summary>
/// <param name="host">
/// Экземпляр <see cref="IDockHost"/>, который будет содержаться в окне.
/// </param>
/// <returns>
/// Объект окна WinUI, который можно отобразить и управлять им.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="host"/> равен null.
/// </exception>
/// <exception cref="ArgumentException">
/// Выбрасывается, если <paramref name="host"/> не является элементом WinUI.
/// </exception>
/// <remarks>
/// Создает окно WinUI с заголовком "Lattice IDE", устанавливает указанный хост
/// в качестве содержимого и регистрирует окно в системе отслеживания окон.
/// Окно создается с настройками по умолчанию для IDE-подобных приложений.
/// </remarks>
public override object CreateMainWindow(IDockHost host)
{
if (host is not FrameworkElement hostElement)
@@ -28,7 +60,25 @@ public sealed class WinUIDockUIService : DockUIServiceBase
return window;
}
/// <inheritdoc/>
/// <summary>
/// Отображает модальное диалоговое окно с указанным содержимым.
/// </summary>
/// <param name="title">Заголовок диалогового окна.</param>
/// <param name="content">Содержимое диалогового окна.</param>
/// <returns>
/// Nullable boolean значение, указывающее результат диалога:
/// true - пользователь подтвердил действие,
/// false - пользователь отменил действие,
/// null - диалог был закрыт без выбора.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="title"/> или <paramref name="content"/> равны null.
/// </exception>
/// <remarks>
/// Создает и показывает ContentDialog с кнопками OK и Cancel.
/// Блокирует взаимодействие с родительским окном до закрытия диалога.
/// Использует XamlRoot активного окна для корректного отображения.
/// </remarks>
public override bool? ShowDialog(string title, object content)
{
if (content is not FrameworkElement contentElement)
@@ -53,7 +103,19 @@ public sealed class WinUIDockUIService : DockUIServiceBase
};
}
/// <inheritdoc/>
/// <summary>
/// Отображает информационное сообщение с кнопкой OK.
/// </summary>
/// <param name="message">Текст сообщения.</param>
/// <param name="caption">Заголовок окна сообщения.</param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="message"/> или <paramref name="caption"/> равны null.
/// </exception>
/// <remarks>
/// Создает ContentDialog с текстом сообщения и одной кнопкой OK.
/// Используется для информирования пользователя о результате операции
/// или отображения некритичных ошибок.
/// </remarks>
public override void ShowMessage(string message, string caption)
{
var dialog = new ContentDialog
@@ -67,7 +129,22 @@ public sealed class WinUIDockUIService : DockUIServiceBase
dialog.ShowAsync();
}
/// <inheritdoc/>
/// <summary>
/// Отображает диалог подтверждения с кнопками Yes/No.
/// </summary>
/// <param name="message">Текст вопроса.</param>
/// <param name="caption">Заголовок окна подтверждения.</param>
/// <returns>
/// true, если пользователь выбрал "Yes"; false, если пользователь выбрал "No".
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="message"/> или <paramref name="caption"/> равны null.
/// </exception>
/// <remarks>
/// Создает ContentDialog с кнопками Yes и No. Используется для получения
/// подтверждения пользователя перед выполнением критических операций,
/// таких как закрытие вкладок с несохраненными данными или сброс настроек.
/// </remarks>
public override bool Confirm(string message, string caption)
{
var dialog = new ContentDialog
@@ -83,7 +160,22 @@ public sealed class WinUIDockUIService : DockUIServiceBase
return result == ContentDialogResult.Primary;
}
/// <inheritdoc/>
/// <summary>
/// Отображает диалог ввода текста.
/// </summary>
/// <param name="prompt">Текст подсказки для пользователя.</param>
/// <param name="defaultValue">Значение по умолчанию для поля ввода.</param>
/// <returns>
/// Введенный пользователем текст или null, если диалог был отменен.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="prompt"/> равен null.
/// </exception>
/// <remarks>
/// Создает ContentDialog с однострочным полем ввода TextBox.
/// Используется для получения текстового ввода от пользователя, такого как
/// имена файлов, названия документов или параметры конфигурации.
/// </remarks>
public override string? Prompt(string prompt, string? defaultValue = null)
{
var textBox = new TextBox
@@ -106,7 +198,19 @@ public sealed class WinUIDockUIService : DockUIServiceBase
return result == ContentDialogResult.Primary ? textBox.Text : null;
}
/// <inheritdoc/>
/// <summary>
/// Выполняет указанное действие в UI-потоке.
/// </summary>
/// <param name="action">Действие для выполнения.</param>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="action"/> равен null.
/// </exception>
/// <remarks>
/// Гарантирует, что действие будет выполнено в потоке, связанном с
/// пользовательским интерфейсом. Если текущий поток уже является UI-потоком,
/// действие выполняется немедленно. В противном случае действие ставится
/// в очередь диспетчера WinUI.
/// </remarks>
public override void InvokeOnUIThread(Action action)
{
if (action == null) return;
@@ -122,7 +226,21 @@ public sealed class WinUIDockUIService : DockUIServiceBase
}
}
/// <inheritdoc/>
/// <summary>
/// Выполняет указанную асинхронную функцию в UI-потоке.
/// </summary>
/// <param name="action">Асинхронная функция для выполнения.</param>
/// <returns>
/// Задача, представляющая асинхронную операцию.
/// </returns>
/// <exception cref="ArgumentNullException">
/// Выбрасывается, если <paramref name="action"/> равен null.
/// </exception>
/// <remarks>
/// Гарантирует, что асинхронная функция будет выполнена в UI-потоке.
/// Используется для операций, которые требуют доступа к UI-элементам
/// или выполняют асинхронные вызовы с обновлением интерфейса.
/// </remarks>
public override async Task InvokeOnUIThreadAsync(Func<Task> action)
{
if (action == null) return;
@@ -151,6 +269,17 @@ public sealed class WinUIDockUIService : DockUIServiceBase
}
}
/// <summary>
/// Получает XamlRoot активного окна приложения.
/// </summary>
/// <returns>
/// XamlRoot активного окна или null, если нет активных окон.
/// </returns>
/// <remarks>
/// Используется для корректного отображения диалоговых окон в контексте
/// текущего окна приложения. Перебирает все зарегистрированные окна
/// и возвращает XamlRoot первого найденного.
/// </remarks>
private XamlRoot? GetActiveXamlRoot()
{
// Получаем XamlRoot из активного окна