421 lines
13 KiB
C#
421 lines
13 KiB
C#
using Lattice.Core.DragDrop.Services;
|
||
using Lattice.Themes;
|
||
using Lattice.UI.DragDrop.WinUI.Factories;
|
||
using Lattice.UI.DragDrop.WinUI.Services;
|
||
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;
|
||
|
||
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}");
|
||
}
|
||
}
|
||
} |