Добавлен example
15
Lattice.Example.DragDrop/App.xaml
Normal file
@@ -0,0 +1,15 @@
|
||||
<Application
|
||||
x:Class="Lattice.Example.DragDrop.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Lattice.Example.DragDrop">
|
||||
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<!-- Fluent Theme Resources -->
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
33
Lattice.Example.DragDrop/App.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Lattice.Themes;
|
||||
using Lattice.Themes.Fluent;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Lattice.Example.DragDrop;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
private Window? _window;
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
// Регистрируем Fluent тему
|
||||
var themeManager = ThemeManager.Current;
|
||||
themeManager.RegisterTheme(new FluentThemePack(false)); // Light тема
|
||||
themeManager.RegisterTheme(new FluentThemePack(true)); // Dark тема
|
||||
|
||||
// Применяем тему по умолчанию
|
||||
themeManager.ApplyTheme("Fluent");
|
||||
|
||||
// Создаем главное окно
|
||||
_window = new MainWindow();
|
||||
_window.Activate();
|
||||
|
||||
// Регистрируем окно в трекере
|
||||
WindowTracker.Register(_window);
|
||||
}
|
||||
}
|
||||
BIN
Lattice.Example.DragDrop/Assets/LockScreenLogo.scale-200.png
Normal file
|
After Width: | Height: | Size: 432 B |
BIN
Lattice.Example.DragDrop/Assets/SplashScreen.scale-200.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
Lattice.Example.DragDrop/Assets/Square150x150Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
Lattice.Example.DragDrop/Assets/Square44x44Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 637 B |
|
After Width: | Height: | Size: 283 B |
BIN
Lattice.Example.DragDrop/Assets/StoreLogo.png
Normal file
|
After Width: | Height: | Size: 456 B |
BIN
Lattice.Example.DragDrop/Assets/Wide310x150Logo.scale-200.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
46
Lattice.Example.DragDrop/Handlers/CustomDropHandler.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Lattice.Core.DragDrop.Abstractions;
|
||||
using Lattice.Core.DragDrop.Models;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Lattice.Example.DragDrop;
|
||||
|
||||
public class CustomDropHandler : IDropTarget
|
||||
{
|
||||
private readonly Action<object> _onDrop;
|
||||
|
||||
public CustomDropHandler(Action<object> onDrop)
|
||||
{
|
||||
_onDrop = onDrop;
|
||||
}
|
||||
|
||||
public async Task<bool> CanAcceptDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
// Принимаем только объекты типа DragDropItem
|
||||
return dropInfo.Data is DragDropItem;
|
||||
}
|
||||
|
||||
public async Task OnDragOverAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data is DragDropItem)
|
||||
{
|
||||
dropInfo.SuggestedEffects = Core.DragDrop.Enums.DragDropEffects.Copy;
|
||||
dropInfo.ShowVisualFeedback = true;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task OnDropAsync(DropInfo dropInfo, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (dropInfo.Data is DragDropItem item)
|
||||
{
|
||||
_onDrop(item);
|
||||
dropInfo.MarkAsHandled();
|
||||
}
|
||||
}
|
||||
|
||||
public Task OnDragLeaveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
67
Lattice.Example.DragDrop/Lattice.Example.DragDrop.csproj
Normal file
@@ -0,0 +1,67 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Lattice.Example.DragDrop</RootNamespace>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<Platforms>x86;x64;ARM64</Platforms>
|
||||
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
|
||||
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<WinUISDKReferences>false</WinUISDKReferences>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.7463" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.8.260101001" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Lattice.Core.DragDrop\Lattice.Core.DragDrop.csproj" />
|
||||
<ProjectReference Include="..\Lattice.Themes.Core\Lattice.Themes.Core.csproj" />
|
||||
<ProjectReference Include="..\Lattice.Themes.Fluent\Lattice.Themes.Fluent.csproj" />
|
||||
<ProjectReference Include="..\Lattice.UI.DragDrop.WinUI\Lattice.UI.DragDrop.WinUI.csproj" />
|
||||
<ProjectReference Include="..\Lattice.UI.DragDrop\Lattice.UI.DragDrop.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
|
||||
Explorer "Package and Publish" context menu entry to be enabled for this project even if
|
||||
the Windows App SDK Nuget package has not yet been restored.
|
||||
-->
|
||||
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Publish Properties -->
|
||||
<PropertyGroup>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
|
||||
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
|
||||
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
|
||||
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
270
Lattice.Example.DragDrop/MainWindow.xaml
Normal file
@@ -0,0 +1,270 @@
|
||||
<Window
|
||||
x:Class="Lattice.Example.DragDrop.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Lattice.Example.DragDrop"
|
||||
xmlns:lattice="using:Lattice.UI.DragDrop.WinUI"
|
||||
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
|
||||
Title="Lattice Drag Drop Example">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Header -->
|
||||
<Border Grid.Row="0"
|
||||
Background="{ThemeResource Lattice.Brush.Accent}"
|
||||
Padding="12">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="12">
|
||||
<FontIcon Glyph=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.OnAccent}"/>
|
||||
<TextBlock Text="Lattice Drag Drop Example"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Title}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.OnAccent}"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="12">
|
||||
<ToggleSwitch Header="Dark Mode"
|
||||
OffContent="Light"
|
||||
OnContent="Dark"
|
||||
Toggled="OnThemeToggleToggled"/>
|
||||
<Button Content="Stats"
|
||||
Click="OnStatsButtonClick"
|
||||
Style="{StaticResource AccentButtonStyle}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Main Content -->
|
||||
<Grid Grid.Row="1" Margin="24">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="4"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Left Panel - Sources -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Primary}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Panel.Border}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Panel}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Panel}"
|
||||
Padding="{ThemeResource Lattice.Spacing.Panel}">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Drag Sources"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Title}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Semibold}"
|
||||
Margin="0,0,0,12"/>
|
||||
<TextBlock Text="Drag items from here to the right panel"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Body}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,16"/>
|
||||
|
||||
<!-- Items that can be dragged -->
|
||||
<ItemsControl x:Name="SourceItemsControl">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Padding="12"
|
||||
Margin="0,0,0,8"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Secondary}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Small}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Thin}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Border.Primary}"
|
||||
lattice:DragDropProperties.IsDragSource="True"
|
||||
lattice:DragDropProperties.DragData="{Binding}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<FontIcon Grid.Column="0"
|
||||
Glyph=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Margin="0,0,12,0"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Body}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Medium}"/>
|
||||
<TextBlock Text="{Binding Description}"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Caption}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Custom drag source example -->
|
||||
<Border Padding="12"
|
||||
Margin="0,16,0,0"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Secondary}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Small}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Thin}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Border.Primary}"
|
||||
x:Name="CustomDragSource">
|
||||
<StackPanel>
|
||||
<TextBlock Text="Custom Drag Source"
|
||||
FontSize="{ThemeResource Lattice.FontSize.BodyStrong}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Semibold}"/>
|
||||
<TextBlock Text="Drag this custom control"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Caption}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"
|
||||
Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Splitter (простой прямоугольник) -->
|
||||
<Rectangle Grid.Column="1"
|
||||
Fill="{ThemeResource Lattice.Brush.Splitter.Normal}"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Rectangle.ContextFlyout>
|
||||
<MenuFlyout>
|
||||
<MenuFlyoutItem Text="Reset Panels" Click="OnResetPanelsClick"/>
|
||||
</MenuFlyout>
|
||||
</Rectangle.ContextFlyout>
|
||||
</Rectangle>
|
||||
|
||||
<!-- Right Panel - Targets -->
|
||||
<Border Grid.Column="2"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Primary}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Panel.Border}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Panel}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Panel}"
|
||||
Padding="{ThemeResource Lattice.Spacing.Panel}"
|
||||
lattice:DragDropProperties.IsDropTarget="True"
|
||||
x:Name="DropTargetArea">
|
||||
<ScrollViewer>
|
||||
<StackPanel>
|
||||
<TextBlock Text="Drop Targets"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Title}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Semibold}"
|
||||
Margin="0,0,0,12"/>
|
||||
<TextBlock Text="Drop items here"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Body}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,16"/>
|
||||
|
||||
<!-- Dropped Items Display -->
|
||||
<ItemsControl x:Name="DroppedItemsControl">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border Padding="12"
|
||||
Margin="0,0,0,8"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Secondary}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Small}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Thin}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Border.Primary}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<FontIcon Grid.Column="0"
|
||||
Glyph=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Margin="0,0,12,0"
|
||||
Foreground="{ThemeResource Lattice.Brush.Success}"/>
|
||||
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding Name}"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Body}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Medium}"/>
|
||||
<TextBlock Text="{Binding Description}"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Caption}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"
|
||||
TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Column="2"
|
||||
Content="Remove"
|
||||
Click="OnRemoveItemClick"
|
||||
Margin="12,0,0,0"
|
||||
Tag="{Binding}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Drop Instructions -->
|
||||
<Border Padding="16"
|
||||
Margin="0,16,0,0"
|
||||
Background="{ThemeResource Lattice.Brush.Drop.Preview}"
|
||||
CornerRadius="{ThemeResource Lattice.CornerRadius.Medium}"
|
||||
BorderThickness="{ThemeResource Lattice.BorderThickness.Medium}"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Accent}"
|
||||
x:Name="DropInstructionsBorder">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
|
||||
<FontIcon Glyph=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="24"
|
||||
Foreground="{ThemeResource Lattice.Brush.Accent}"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0,0,0,12"/>
|
||||
<TextBlock Text="Drop items here"
|
||||
FontSize="{ThemeResource Lattice.FontSize.BodyStrong}"
|
||||
FontWeight="{ThemeResource Lattice.FontWeight.Medium}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Accent}"
|
||||
HorizontalAlignment="Center"/>
|
||||
<TextBlock Text="Drag and drop items from the left panel"
|
||||
FontSize="{ThemeResource Lattice.FontSize.Caption}"
|
||||
Foreground="{ThemeResource Lattice.Brush.Accent}"
|
||||
HorizontalAlignment="Center"
|
||||
Opacity="0.7"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</Grid>
|
||||
|
||||
<!-- Status Bar -->
|
||||
<Border Grid.Row="2"
|
||||
Background="{ThemeResource Lattice.Brush.Background.Secondary}"
|
||||
BorderThickness="1,0,0,0"
|
||||
BorderBrush="{ThemeResource Lattice.Brush.Border.Primary}"
|
||||
Padding="12">
|
||||
<Grid>
|
||||
<TextBlock x:Name="StatusText"
|
||||
Text="Ready"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="12"
|
||||
HorizontalAlignment="Right">
|
||||
<TextBlock x:Name="DragStatsText"
|
||||
Text="Drag operations: 0"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"/>
|
||||
<TextBlock Text="|"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Disabled}"/>
|
||||
<TextBlock x:Name="DropStatsText"
|
||||
Text="Dropped items: 0"
|
||||
Foreground="{ThemeResource Lattice.Brush.Text.Secondary}"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
421
Lattice.Example.DragDrop/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,421 @@
|
||||
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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Lattice.Example.DragDrop/Models/DragDropItem.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Lattice.Example.DragDrop;
|
||||
|
||||
public class DragDropItem : INotifyPropertyChanged
|
||||
{
|
||||
private string _name = string.Empty;
|
||||
private string _description = string.Empty;
|
||||
private string _icon = string.Empty;
|
||||
private string _type = string.Empty;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => _name;
|
||||
set
|
||||
{
|
||||
if (_name != value)
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(nameof(Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get => _description;
|
||||
set
|
||||
{
|
||||
if (_description != value)
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(nameof(Description));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Icon
|
||||
{
|
||||
get => _icon;
|
||||
set
|
||||
{
|
||||
if (_icon != value)
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(nameof(Icon));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string Type
|
||||
{
|
||||
get => _type;
|
||||
set
|
||||
{
|
||||
if (_type != value)
|
||||
{
|
||||
_type = value;
|
||||
OnPropertyChanged(nameof(Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
|
||||
public override string ToString() => $"{Name} ({Type})";
|
||||
}
|
||||
51
Lattice.Example.DragDrop/Package.appxmanifest
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="dcfd6640-86d9-4ce7-bc17-24685f01b577"
|
||||
Publisher="CN=frost"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="dcfd6640-86d9-4ce7-bc17-24685f01b577" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Lattice.Example.DragDrop</DisplayName>
|
||||
<PublisherDisplayName>frost</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="Lattice.Example.DragDrop"
|
||||
Description="Lattice.Example.DragDrop"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
27
Lattice.Example.DragDrop/PriorityToTextConverter.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using System;
|
||||
|
||||
namespace Lattice.Example.DragDrop;
|
||||
|
||||
public class PriorityToTextConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
if (value is int priority)
|
||||
{
|
||||
return priority switch
|
||||
{
|
||||
1 => "🔥 High",
|
||||
2 => "⚠️ Medium",
|
||||
3 => "📋 Low",
|
||||
_ => $"Priority {priority}"
|
||||
};
|
||||
}
|
||||
return "Normal";
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
10
Lattice.Example.DragDrop/Properties/launchSettings.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Lattice.Example.DragDrop (Package)": {
|
||||
"commandName": "MsixPackage"
|
||||
},
|
||||
"Lattice.Example.DragDrop (Unpackaged)": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Lattice.Example.DragDrop/WindowExtensions.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
namespace Lattice.Example.DragDrop;
|
||||
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static void SetWindowSize(this Window window, int width, int height)
|
||||
{
|
||||
var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);
|
||||
var windowId = Microsoft.UI.Win32Interop.GetWindowIdFromWindow(hwnd);
|
||||
var appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
|
||||
|
||||
appWindow.Resize(new Windows.Graphics.SizeInt32(width, height));
|
||||
}
|
||||
}
|
||||
19
Lattice.Example.DragDrop/app.manifest
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="Lattice.Example.DragDrop.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- The ID below informs the system that this application is compatible with OS features first introduced in Windows 10.
|
||||
It is necessary to support features in unpackaged applications, for example the custom titlebar implementation.
|
||||
For more info see https://docs.microsoft.com/windows/apps/windows-app-sdk/use-windows-app-sdk-run-time#declare-os-compatibility-in-your-application-manifest -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
||||