DragAndDrop core
This commit is contained in:
227
Lattice.Core.DragDrop/Models/DragInfo.cs
Normal file
227
Lattice.Core.DragDrop/Models/DragInfo.cs
Normal file
@@ -0,0 +1,227 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
269
Lattice.Core.DragDrop/Models/DropInfo.cs
Normal file
269
Lattice.Core.DragDrop/Models/DropInfo.cs
Normal file
@@ -0,0 +1,269 @@
|
||||
using Lattice.Core.DragDrop.Enums;
|
||||
using Lattice.Core.Geometry;
|
||||
|
||||
namespace Lattice.Core.DragDrop.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Содержит информацию о потенциальном или фактическом сбросе в операции перетаскивания.
|
||||
/// Этот класс используется для передачи данных между системой перетаскивания
|
||||
/// и целью сброса (<see cref="Abstractions.IDropTarget"/>).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// <see cref="DropInfo"/> предоставляет цель сброса всей необходимой информацией
|
||||
/// для принятия решения о возможности сброса и выполнения соответствующей операции.
|
||||
/// Ключевые аспекты включают:
|
||||
/// </para>
|
||||
/// <list type="bullet">
|
||||
/// <item>Предлагаемые для сброса данные</item>
|
||||
/// <item>Текущую позицию курсора</item>
|
||||
/// <item>Разрешенные эффекты от источника</item>
|
||||
/// <item>Предлагаемые эффекты для сброса</item>
|
||||
/// <item>Ссылку на цель сброса</item>
|
||||
/// <item>Флаг обработки операции</item>
|
||||
/// </list>
|
||||
/// <para>
|
||||
/// Этот класс является изменяемым, позволяя цели сброса обновлять предлагаемые
|
||||
/// эффекты и помечать операцию как обработанную.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class DropInfo
|
||||
{
|
||||
private DragDropEffects _effects = DragDropEffects.None;
|
||||
public DropPosition DropPosition { get; set; } = DropPosition.Inside;
|
||||
public bool ShowVisualFeedback { get; set; } = true;
|
||||
public object? VisualFeedbackData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает данные, которые предлагаются для сброса.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Данные, переданные от источника перетаскивания, или null, если данные
|
||||
/// не доступны или операция была отменена.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Эти данные соответствуют свойству <see cref="DragInfo.Data"/> из
|
||||
/// исходной информации о перетаскивании.
|
||||
/// </remarks>
|
||||
public object? Data { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает текущую позицию курсора в координатах экрана.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Точка в экранных координатах, представляющая текущее положение курсора
|
||||
/// мыши во время операции перетаскивания.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Эта позиция используется для определения точного места сброса и может
|
||||
/// влиять на предлагаемые эффекты (например, различные операции для
|
||||
/// разных областей цели сброса).
|
||||
/// </remarks>
|
||||
public Point Position { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает разрешенные эффекты от источника перетаскивания.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Комбинация флагов <see cref="Enums.DragDropEffects"/>, определяющая,
|
||||
/// какие операции разрешил источник.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Цель сброса должна уважать эти ограничения и не предлагать эффекты,
|
||||
/// которые не разрешены источником.
|
||||
/// </remarks>
|
||||
public Enums.DragDropEffects AllowedEffects { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает предлагаемые эффекты для операции сброса.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Комбинация флагов <see cref="Enums.DragDropEffects"/>, предлагаемая
|
||||
/// целью сброса. По умолчанию равно <see cref="Enums.DragDropEffects.None"/>.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Цель сброса должна установить это свойство в методе <see cref="Abstractions.IDropTarget.DragOver"/>
|
||||
/// на основе анализа предоставленных данных и текущего контекста.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Если цель не устанавливает это свойство, система перетаскивания
|
||||
/// будет использовать эффекты по умолчанию.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public Enums.DragDropEffects SuggestedEffects
|
||||
{
|
||||
get => _effects;
|
||||
set => _effects = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получает цель сброса, которая обрабатывает эту информацию.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Объект, реализующий <see cref="Abstractions.IDropTarget"/>, или null,
|
||||
/// если цель не определена.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Эта ссылка позволяет системе идентифицировать, какая цель обрабатывает
|
||||
/// информацию о сбросе, и используется для отслеживания изменений цели
|
||||
/// во время операции перетаскивания.
|
||||
/// </remarks>
|
||||
public object? Target { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает или задает дополнительные параметры, специфичные для конкретной
|
||||
/// реализации перетаскивания.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// Словарь, содержащий пары ключ-значение с дополнительными параметрами.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// Может использоваться для передачи контекстной информации между
|
||||
/// различными компонентами системы перетаскивания или для хранения
|
||||
/// временных данных во время обработки операции.
|
||||
/// </remarks>
|
||||
public Dictionary<string, object> Parameters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Получает значение, указывающее, был ли сброс уже обработан.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// true, если операция сброса была помечена как обработанная;
|
||||
/// в противном случае — false.
|
||||
/// </value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Это свойство используется для предотвращения множественной обработки
|
||||
/// одной и той же операции сброса. После вызова метода <see cref="MarkAsHandled"/>,
|
||||
/// свойство становится true.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Система перетаскивания может проверять это свойство, чтобы определить,
|
||||
/// нужно ли выполнять дополнительную обработку по умолчанию.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool Handled { get; private set; }
|
||||
|
||||
/// <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>
|
||||
/// Инициализирует новый экземпляр класса <see cref="DropInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="data">
|
||||
/// Данные, которые предлагаются для сброса. Может быть null.
|
||||
/// </param>
|
||||
/// <param name="position">
|
||||
/// Текущая позиция курсора в координатах экрана.
|
||||
/// </param>
|
||||
/// <param name="allowedEffects">
|
||||
/// Разрешенные эффекты от источника перетаскивания.
|
||||
/// </param>
|
||||
/// <param name="target">
|
||||
/// Цель сброса, которая обрабатывает эту информацию. Может быть null.
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Конструктор создает экземпляр <see cref="DropInfo"/> с указанными
|
||||
/// параметрами, инициализирует коллекцию параметров пустым словарем
|
||||
/// и устанавливает флаг <see cref="Handled"/> в false.
|
||||
/// </remarks>
|
||||
public DropInfo(object? data, Point position, Enums.DragDropEffects allowedEffects, object? target = null)
|
||||
{
|
||||
Data = data;
|
||||
Position = position;
|
||||
AllowedEffects = allowedEffects;
|
||||
Target = target;
|
||||
Parameters = new Dictionary<string, object>();
|
||||
Handled = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Помечает сброс как обработанный.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Этот метод должен вызываться целью сброса в методе <see cref="Abstractions.IDropTarget.Drop"/>,
|
||||
/// если она успешно обработала операцию сброса.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// После вызова этого метода свойство <see cref="Handled"/> становится true,
|
||||
/// что сигнализирует системе перетаскивания о том, что дополнительная
|
||||
/// обработка не требуется.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public void MarkAsHandled()
|
||||
{
|
||||
Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Создает новый экземпляр <see cref="DropInfo"/> с теми же данными,
|
||||
/// но новой позицией.
|
||||
/// </summary>
|
||||
/// <param name="newPosition">
|
||||
/// Новая позиция для информации о сбросе.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// Новый экземпляр <see cref="DropInfo"/> с обновленной позицией.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// Этот метод используется для обновления информации о сбросе при
|
||||
/// перемещении курсора, сохраняя исходные данные и параметры.
|
||||
/// </remarks>
|
||||
public DropInfo WithPosition(Point newPosition)
|
||||
{
|
||||
return new DropInfo(Data, newPosition, AllowedEffects, Target)
|
||||
{
|
||||
Parameters = new Dictionary<string, object>(Parameters),
|
||||
SuggestedEffects = _effects,
|
||||
DropPosition = DropPosition,
|
||||
ShowVisualFeedback = ShowVisualFeedback,
|
||||
VisualFeedbackData = VisualFeedbackData
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка установки эффекта перетаскивания в разрешенные эффекты.
|
||||
/// </summary>
|
||||
public bool CanAcceptEffect(Enums.DragDropEffects effect)
|
||||
{
|
||||
return (AllowedEffects & effect) != Enums.DragDropEffects.None;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user