Доработан 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

@@ -1,421 +1,17 @@
using Lattice.Core.DragDrop.Services;
using Lattice.Themes;
using Lattice.UI.DragDrop.WinUI.Factories;
using Lattice.UI.DragDrop.WinUI.Services;
using Lattice.UI.DragDrop.WinUI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
namespace Lattice.Example.DragDrop;
public sealed partial class MainWindow : Window
{
private readonly ObservableCollection<DragDropItem> _sourceItems = new();
private readonly ObservableCollection<DragDropItem> _droppedItems = new();
private WinUIDragDropManager? _dragDropManager;
private IDragDropService? _dragDropService;
private int _dragOperationCount = 0;
private bool _isInitialized = false;
public MainWindow()
{
// Создаем менеджер перетаскивания
_dragDropManager = WinUIDragDropFactory.CreateManager(this, manager =>
{
// Настраиваем смещение визуального элемента
manager.DragVisualOffset = new Core.Geometry.Point(-15, -15);
});
_dragDropService = _dragDropManager.DragDropService;
InitializeComponent();
// Устанавливаем размер окна
SetWindowSize(1200, 800);
// Инициализируем данные
InitializeData();
// Инициализируем drag & drop систему
InitializeDragDrop();
// Устанавливаем контекст данных
SourceItemsControl.ItemsSource = _sourceItems;
DroppedItemsControl.ItemsSource = _droppedItems;
Closed += MainWindow_Closing;
// Обновляем видимость инструкций
UpdateDropInstructions();
}
private void MainWindow_Closing(object sender, WindowEventArgs args)
{
// Очищаем ресурсы
_dragDropManager?.Dispose();
}
private void InitializeData()
{
// Создаем тестовые данные для перетаскивания
_sourceItems.Add(new DragDropItem
{
Name = "Document",
Description = "Microsoft Word document",
Icon = "Document",
Type = "File"
});
_sourceItems.Add(new DragDropItem
{
Name = "Image",
Description = "PNG image file",
Icon = "Pictures",
Type = "File"
});
_sourceItems.Add(new DragDropItem
{
Name = "Music",
Description = "MP3 audio file",
Icon = "Audio",
Type = "File"
});
_sourceItems.Add(new DragDropItem
{
Name = "Video",
Description = "MP4 video file",
Icon = "Video",
Type = "File"
});
_sourceItems.Add(new DragDropItem
{
Name = "Contact",
Description = "Contact information",
Icon = "Contact",
Type = "Data"
});
_sourceItems.Add(new DragDropItem
{
Name = "Link",
Description = "Web URL",
Icon = "Link",
Type = "Link"
});
_sourceItems.Add(new DragDropItem
{
Name = "Folder",
Description = "File system folder",
Icon = "Folder",
Type = "Folder"
});
}
private void InitializeDragDrop()
{
try
{
// Настраиваем кастомный источник перетаскивания
_dragDropManager.MakeDragSource(CustomDragSource, new DragDropItem
{
Name = "Custom Element",
Description = "This is a custom drag source example",
Icon = "Favorite",
Type = "Custom"
});
// Настраиваем обработчик для области сброса
_dragDropManager.MakeDropTarget(DropTargetArea);
// Подписываемся на события перетаскивания
_dragDropService.DragStarted += OnDragStarted;
_dragDropService.DragUpdated += OnDragUpdated;
_dragDropService.DragCompleted += OnDragCompleted;
_dragDropService.DragCancelled += OnDragCancelled;
_dragDropService.DropTargetChanged += OnDropTargetChanged;
_dragDropService.ErrorOccurred += OnDragDropError;
UpdateStats();
StatusText.Text = "Drag & Drop system initialized";
}
catch (Exception ex)
{
StatusText.Text = $"Failed to initialize Drag & Drop: {ex.Message}";
ShowErrorDialog("Initialization Error", ex.Message);
}
}
private void OnDragStarted(object? sender, Core.DragDrop.Services.DragStartedEventArgs e)
{
_dragOperationCount++;
UpdateStats();
StatusText.Text = $"Dragging started: {GetItemName(e.DragInfo.Data)}";
}
private void OnDragUpdated(object? sender, Core.DragDrop.Services.DragUpdatedEventArgs e)
{
StatusText.Text = $"Dragging: {GetItemName(e.DragInfo.Data)} at ({e.Position.X:F0}, {e.Position.Y:F0})";
}
private void OnDragCompleted(object? sender, Core.DragDrop.Services.DragCompletedEventArgs e)
{
// Проверяем, что элемент сброшен на нашу область
if (e.DragInfo.Data is DragDropItem item)
{
// Добавляем элемент в список сброшенных
DispatcherQueue.TryEnqueue(() =>
{
if (!_droppedItems.Contains(item))
{
_droppedItems.Add(item);
// Удаляем из источников, если это не кастомный элемент
if (_sourceItems.Contains(item) && item.Name != "Custom Element")
{
_sourceItems.Remove(item);
}
UpdateStats();
UpdateDropInstructions();
StatusText.Text = $"Item dropped: {item.Name}";
// Показываем уведомление
ShowDropNotification(item);
}
});
}
else
{
StatusText.Text = "Drag completed";
}
}
private async void ShowDropNotification(DragDropItem item)
{
var notification = new TeachingTip
{
Title = "Item Dropped",
Subtitle = $"Successfully dropped '{item.Name}'",
IsOpen = true,
PreferredPlacement = TeachingTipPlacementMode.TopRight,
Target = DropTargetArea
};
// Автоматически скрываем через 3 секунды
await Task.Delay(3000);
notification.IsOpen = false;
}
private void OnDragCancelled(object? sender, Core.DragDrop.Services.DragCancelledEventArgs e)
{
StatusText.Text = "Drag cancelled";
}
private void OnDropTargetChanged(object? sender, Core.DragDrop.Services.DropTargetChangedEventArgs e)
{
if (e.Target != null)
{
StatusText.Text = "Over drop target";
}
else
{
StatusText.Text = "Not over drop target";
}
}
private async void OnDragDropError(object? sender, Core.DragDrop.Services.DragDropErrorEventArgs e)
{
StatusText.Text = $"Error: {e.Exception.Message}";
await ShowErrorDialog("Drag & Drop Error", e.Exception.Message);
}
private string GetItemName(object? data)
{
if (data is DragDropItem item)
{
return item.Name;
}
return data?.ToString() ?? "Unknown";
}
private void UpdateStats()
{
DispatcherQueue.TryEnqueue(() =>
{
DragStatsText.Text = $"Drag operations: {_dragOperationCount}";
DropStatsText.Text = $"Dropped items: {_droppedItems.Count}";
});
}
private void UpdateDropInstructions()
{
DropInstructionsBorder.Visibility = _droppedItems.Count == 0 ?
Visibility.Visible : Visibility.Collapsed;
}
private void OnThemeToggleToggled(object sender, RoutedEventArgs e)
{
if (sender is ToggleSwitch toggle)
{
try
{
var themeManager = ThemeManager.Current;
if (toggle.IsOn)
{
themeManager.ApplyTheme("Fluent Dark");
}
else
{
themeManager.ApplyTheme("Fluent");
}
StatusText.Text = $"Theme changed to {(toggle.IsOn ? "Dark" : "Light")}";
}
catch (Exception ex)
{
StatusText.Text = $"Failed to change theme: {ex.Message}";
}
}
}
private async void OnStatsButtonClick(object sender, RoutedEventArgs e)
{
if (_dragDropService != null)
{
var stats = _dragDropService.GetStats();
var dialog = new ContentDialog
{
Title = "Drag & Drop Statistics",
Content = new ScrollViewer
{
Content = new StackPanel
{
Spacing = 8,
Children =
{
CreateStatRow("Total Drag Operations:", stats.TotalDragOperations.ToString()),
CreateStatRow("Successful Drops:", stats.SuccessfulDrops.ToString()),
CreateStatRow("Cancelled Operations:", stats.CancelledOperations.ToString()),
CreateStatRow("Errors:", stats.ErrorCount.ToString()),
CreateStatRow("Registered Targets:", stats.RegisteredTargets.ToString()),
CreateStatRow("Average Operation Time:",
stats.AverageOperationTime.TotalMilliseconds.ToString("F0") + "ms")
}
}
},
PrimaryButtonText = "OK",
XamlRoot = Content.XamlRoot
};
await dialog.ShowAsync();
}
}
private StackPanel CreateStatRow(string label, string value)
{
return new StackPanel
{
Orientation = Orientation.Horizontal,
Spacing = 10,
Children =
{
new TextBlock
{
Text = label,
FontWeight = Microsoft.UI.Text.FontWeights.SemiBold,
Width = 200
},
new TextBlock
{
Text = value
}
}
};
}
private void OnRemoveItemClick(object sender, RoutedEventArgs e)
{
if (sender is Button button && button.Tag is DragDropItem item)
{
_droppedItems.Remove(item);
UpdateStats();
UpdateDropInstructions();
// Добавляем обратно в источники, если это не кастомный элемент
if (item.Name != "Custom Element" && !_sourceItems.Contains(item))
{
_sourceItems.Add(item);
}
StatusText.Text = $"Item removed: {item.Name}";
}
}
private void OnResetPanelsClick(object sender, RoutedEventArgs e)
{
// Очищаем все сброшенные элементы
foreach (var item in _droppedItems.ToList())
{
if (item.Name != "Custom Element" && !_sourceItems.Contains(item))
{
_sourceItems.Add(item);
}
}
_droppedItems.Clear();
UpdateStats();
UpdateDropInstructions();
StatusText.Text = "Panels reset";
}
private async Task ShowErrorDialog(string title, string message)
{
var dialog = new ContentDialog
{
Title = title,
Content = message,
PrimaryButtonText = "OK",
XamlRoot = Content.XamlRoot
};
await dialog.ShowAsync();
}
// Метод для установки размера окна
private void SetWindowSize(int width, int height)
{
try
{
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
appWindow.Resize(new Windows.Graphics.SizeInt32(width, height));
// Центрируем окно
var displayArea = Microsoft.UI.Windowing.DisplayArea.GetFromWindowId(windowId,
Microsoft.UI.Windowing.DisplayAreaFallback.Primary);
var centerX = (displayArea.WorkArea.Width - width) / 2;
var centerY = (displayArea.WorkArea.Height - height) / 2;
appWindow.Move(new Windows.Graphics.PointInt32(centerX, centerY));
}
catch (Exception ex)
{
// Игнорируем ошибки при установке размера окна
System.Diagnostics.Debug.WriteLine($"Failed to set window size: {ex.Message}");
}
XamlInitializer.Initialize(this);
Title = "✅ Drag & Drop работает! Перетащите элементы →";
}
}