A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

168 lines
6.1 KiB

using System;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage;
namespace ControlCatalog.Pages
{
public class DragAndDropPage : UserControl
{
private readonly TextBlock _dropState;
private readonly DataFormat<string> _customFormat =
DataFormat.CreateStringApplicationFormat("xxx-avalonia-controlcatalog-custom");
public DragAndDropPage()
{
InitializeComponent();
_dropState = this.Get<TextBlock>("DropState");
int textCount = 0;
SetupDnd(
"Text",
d => d.Add(DataTransferItem.Create(DataFormat.Text, $"Text was dragged {++textCount} times")),
DragDropEffects.Copy | DragDropEffects.Move | DragDropEffects.Link);
SetupDnd(
"Custom",
d => d.Add(DataTransferItem.Create(_customFormat, "Test123")),
DragDropEffects.Copy | DragDropEffects.Move);
SetupDnd(
"Files",
async d =>
{
if (Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName is { } name &&
TopLevel.GetTopLevel(this) is { } topLevel &&
await topLevel.StorageProvider.TryGetFileFromPathAsync(name) is { } storageFile)
{
d.Add(DataTransferItem.Create(DataFormat.File, storageFile));
}
},
DragDropEffects.Copy);
}
private void SetupDnd(string suffix, Action<DataTransfer> factory, DragDropEffects effects) =>
SetupDnd(
suffix,
o =>
{
factory(o);
return Task.CompletedTask;
},
effects);
private void SetupDnd(string suffix, Func<DataTransfer, Task> factory, DragDropEffects effects)
{
var dragMe = this.Get<Border>("DragMe" + suffix);
var dragState = this.Get<TextBlock>("DragState" + suffix);
async void DoDrag(object? sender, PointerPressedEventArgs e)
{
var dragData = new DataTransfer();
await factory(dragData);
var result = await DragDrop.DoDragDropAsync(e, dragData, effects);
switch (result)
{
case DragDropEffects.Move:
dragState.Text = "Data was moved";
break;
case DragDropEffects.Copy:
dragState.Text = "Data was copied";
break;
case DragDropEffects.Link:
dragState.Text = "Data was linked";
break;
case DragDropEffects.None:
dragState.Text = "The drag operation was canceled";
break;
default:
dragState.Text = "Unknown result";
break;
}
}
void DragOver(object? sender, DragEventArgs e)
{
if (e.Source is Control c && c.Name == "MoveTarget")
{
e.DragEffects = e.DragEffects & (DragDropEffects.Move);
}
else
{
e.DragEffects = e.DragEffects & (DragDropEffects.Copy);
}
// Only allow if the dragged data contains text or filenames.
if (!e.DataTransfer.Contains(DataFormat.Text)
&& !e.DataTransfer.Contains(DataFormat.File)
&& !e.DataTransfer.Contains(_customFormat))
e.DragEffects = DragDropEffects.None;
}
async void Drop(object? sender, DragEventArgs e)
{
if (e.Source is Control c && c.Name == "MoveTarget")
{
e.DragEffects = e.DragEffects & (DragDropEffects.Move);
}
else
{
e.DragEffects = e.DragEffects & (DragDropEffects.Copy);
}
if (e.DataTransfer.Contains(DataFormat.Text))
{
_dropState.Text = e.DataTransfer.TryGetText();
}
else if (e.DataTransfer.Contains(DataFormat.File))
{
var files = e.DataTransfer.TryGetFiles() ?? [];
var contentStr = "";
foreach (var item in files)
{
if (item is IStorageFile file)
{
var content = await DialogsPage.ReadTextFromFile(file, 500);
contentStr += $"File {item.Name}:{Environment.NewLine}{content}{Environment.NewLine}{Environment.NewLine}";
}
else if (item is IStorageFolder folder)
{
var childrenCount = 0;
await foreach (var _ in folder.GetItemsAsync())
{
childrenCount++;
}
contentStr += $"Folder {item.Name}: items {childrenCount}{Environment.NewLine}{Environment.NewLine}";
}
}
_dropState.Text = contentStr;
}
else if (e.DataTransfer.Contains(_customFormat))
{
_dropState.Text = "Custom: " + e.DataTransfer.TryGetValue(_customFormat);
}
}
dragMe.PointerPressed += DoDrag;
AddHandler(DragDrop.DropEvent, Drop);
AddHandler(DragDrop.DragOverEvent, DragOver);
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}