227 lines
10 KiB
C#
227 lines
10 KiB
C#
using Lattice.Core.Geometry;
|
||
using System.Collections.Concurrent;
|
||
|
||
namespace Lattice.Core.DragDrop.Models;
|
||
|
||
/// <summary>
|
||
/// Содержит информацию о начале операции перетаскивания.
|
||
/// Этот класс передается от источника перетаскивания к системе перетаскивания
|
||
/// для инициализации и управления операцией.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// <para>
|
||
/// <see cref="DragInfo"/> является ключевым компонентом системы перетаскивания,
|
||
/// инкапсулирующим все необходимые данные для начала операции. Он содержит:
|
||
/// </para>
|
||
/// <list type="bullet">
|
||
/// <item>Данные для передачи</item>
|
||
/// <item>Разрешенные эффекты перетаскивания</item>
|
||
/// <item>Начальную позицию операции</item>
|
||
/// <item>Ссылку на источник перетаскивания</item>
|
||
/// <item>Дополнительные параметры операции</item>
|
||
/// </list>
|
||
/// <para>
|
||
/// Этот класс используется как внутренний механизм передачи данных между
|
||
/// <see cref="Abstractions.IDragSource"/> и системой управления перетаскиванием.
|
||
/// </para>
|
||
/// </remarks>
|
||
public class DragInfo : IDisposable, ICloneable
|
||
{
|
||
private readonly ConcurrentDictionary<string, object> _parameters = new();
|
||
private bool _disposed;
|
||
|
||
/// <summary>
|
||
/// Получает данные, которые передаются в операции перетаскивания.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Объект, содержащий данные для передачи. Может быть любого типа,
|
||
/// поддерживаемого системой перетаскивания.
|
||
/// </value>
|
||
/// <remarks>
|
||
/// Эти данные будут доступны цели сброса через <see cref="DropInfo.Data"/>.
|
||
/// Важно, чтобы данные были сериализуемыми, если операция перетаскивания
|
||
/// может выходить за пределы процесса приложения.
|
||
/// </remarks>
|
||
public object Data { get; }
|
||
|
||
/// <summary>
|
||
/// Получает разрешенные эффекты для этой операции перетаскивания.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Комбинация флагов <see cref="Enums.DragDropEffects"/>, определяющая,
|
||
/// какие операции разрешены для этого перетаскивания.
|
||
/// </value>
|
||
/// <remarks>
|
||
/// Этот параметр используется системой для фильтрации допустимых операций
|
||
/// и предоставления соответствующей визуальной обратной связи пользователю.
|
||
/// </remarks>
|
||
public Enums.DragDropEffects AllowedEffects { get; }
|
||
|
||
/// <summary>
|
||
/// Получает начальную позицию операции перетаскивания в координатах экрана.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Точка в экранных координатах, где была начата операция перетаскивания.
|
||
/// </value>
|
||
/// <remarks>
|
||
/// Эта позиция используется для вычисления смещения при создании визуального
|
||
/// представления перетаскивания и для определения порога начала операции.
|
||
/// </remarks>
|
||
public Point StartPosition { get; }
|
||
|
||
/// <summary>
|
||
/// Получает источник перетаскивания, который инициировал операцию.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Объект, реализующий <see cref="Abstractions.IDragSource"/>, или null,
|
||
/// если источник не доступен или не требуется.
|
||
/// </value>
|
||
/// <remarks>
|
||
/// Эта ссылка может использоваться для уведомления источника о результате
|
||
/// операции перетаскивания (завершении или отмене).
|
||
/// </remarks>
|
||
public object? Source { get; }
|
||
|
||
/// <summary>
|
||
/// Получает или задает дополнительные параметры, специфичные для конкретной
|
||
/// реализации перетаскивания.
|
||
/// </summary>
|
||
/// <value>
|
||
/// Словарь, содержащий пары ключ-значение с дополнительными параметрами.
|
||
/// </value>
|
||
/// <remarks>
|
||
/// Используется для передачи контекстной информации, которая не входит
|
||
/// в стандартный набор свойств, но может быть полезной для обработки
|
||
/// операции перетаскивания.
|
||
/// </remarks>
|
||
public IReadOnlyDictionary<string, object> Parameters => _parameters;
|
||
|
||
/// <summary>
|
||
/// Инициализирует новый экземпляр класса <see cref="DragInfo"/>.
|
||
/// </summary>
|
||
/// <param name="data">
|
||
/// Данные, которые передаются в операции перетаскивания.
|
||
/// Не может быть null.
|
||
/// </param>
|
||
/// <param name="allowedEffects">
|
||
/// Разрешенные эффекты для этой операции перетаскивания.
|
||
/// </param>
|
||
/// <param name="startPosition">
|
||
/// Начальная позиция операции перетаскивания в координатах экрана.
|
||
/// </param>
|
||
/// <param name="source">
|
||
/// Источник перетаскивания, который инициировал операцию. Может быть null.
|
||
/// </param>
|
||
/// <exception cref="ArgumentNullException">
|
||
/// Выбрасывается, когда <paramref name="data"/> равен null.
|
||
/// </exception>
|
||
/// <remarks>
|
||
/// Конструктор создает экземпляр <see cref="DragInfo"/> с указанными
|
||
/// параметрами и инициализирует коллекцию параметров пустым словарем.
|
||
/// </remarks>
|
||
public DragInfo(object data, Enums.DragDropEffects allowedEffects, Point startPosition, object? source = null)
|
||
{
|
||
Data = data ?? throw new ArgumentNullException(nameof(data));
|
||
AllowedEffects = allowedEffects;
|
||
StartPosition = startPosition;
|
||
Source = source;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает новый экземпляр <see cref="DragInfo"/> с теми же данными,
|
||
/// но новой позицией.
|
||
/// </summary>
|
||
/// <param name="newPosition">
|
||
/// Новая позиция для информации о перетаскивании.
|
||
/// </param>
|
||
/// <returns>
|
||
/// Новый экземпляр <see cref="DragInfo"/> с обновленной позицией.
|
||
/// </returns>
|
||
/// <remarks>
|
||
/// Этот метод используется для обновления информации о перетаскивании
|
||
/// при перемещении курсора, сохраняя исходные данные и параметры.
|
||
/// </remarks>
|
||
public DragInfo CloneWithPosition(Point newPosition)
|
||
{
|
||
ThrowIfDisposed();
|
||
|
||
var clone = new DragInfo(Data, AllowedEffects, newPosition, Source);
|
||
|
||
foreach (var kvp in _parameters)
|
||
{
|
||
clone._parameters[kvp.Key] = kvp.Value;
|
||
}
|
||
|
||
return clone;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Создает новый экземпляр <see cref="DragInfo"/> с теми же данными.
|
||
/// </summary>
|
||
public DragInfo Clone() => new DragInfo(Data, AllowedEffects, StartPosition, Source);
|
||
|
||
/// <inheritdoc/>
|
||
object ICloneable.Clone() => this.Clone();
|
||
|
||
/// <summary>
|
||
/// Получает или дополнительные параметры, специфичные для конкретной
|
||
/// реализации перетаскивания.
|
||
/// </summary>
|
||
public T? GetParameter<T>(string key, T? defaultValue = default)
|
||
{
|
||
if (Parameters.TryGetValue(key, out var value) && value is T typedValue)
|
||
{
|
||
return typedValue;
|
||
}
|
||
return defaultValue;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Получает или дополнительные параметры, специфичные для конкретной
|
||
/// реализации перетаскивания.
|
||
/// </summary>
|
||
public bool TryGetParameter<T>(string key, out T? value)
|
||
{
|
||
value = default;
|
||
|
||
if (_parameters.TryGetValue(key, out var objValue) && objValue is T typedValue)
|
||
{
|
||
value = typedValue;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Задает дополнительные параметры, специфичные для конкретной
|
||
/// реализации перетаскивания.
|
||
/// </summary>
|
||
public void SetParameter<T>(string key, T value)
|
||
{
|
||
_parameters[key] = value!;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Освобождает ресурсы.
|
||
/// </summary>
|
||
public void Dispose()
|
||
{
|
||
if (_disposed) return;
|
||
|
||
_parameters.Clear();
|
||
_disposed = true;
|
||
GC.SuppressFinalize(this);
|
||
}
|
||
|
||
private void ThrowIfDisposed()
|
||
{
|
||
if (_disposed)
|
||
throw new ObjectDisposedException(nameof(DragInfo));
|
||
}
|
||
|
||
~DragInfo()
|
||
{
|
||
Dispose();
|
||
}
|
||
} |