5

I'm trying to implement Drag & Drop with files on a ListBox which is contained in a Window of an Avalonia project.
As I couldn't get it working and I thought that ListBox perhaps is a special case, I tried to make a similar example like the one from ControlCatalogStandalone.
While the code in ControlCatalogStandalone works as expected, virtually the same code in my test application doesn't work properly.
The relevant code in ControlCatalogStandalone belongs to a UserControl, where in my application it belongs to the MainWindow. Could this be the cause for the misbehavior?
I created a new Avalonia MVVM Application based on the NuGet packages 0.9.11 in Visual Studio 2019.
I also tried version 0.10.0-preview2 in vain.
This is the XAML file:

<Window xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:DragAndDropTests.ViewModels;assembly=DragAndDropTests"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" Width="400" Height="200"
        x:Class="DragAndDropTests.Views.MainWindow"
        Icon="/Assets/avalonia-logo.ico"
        Title="DragAndDropTests">

    <Design.DataContext>
        <vm:MainWindowViewModel/>
    </Design.DataContext>

    <StackPanel Orientation="Vertical" Spacing="4">
        <TextBlock Classes="h1">Drag+Drop</TextBlock>
        <TextBlock Classes="h2">Example of Drag+Drop capabilities</TextBlock>

        <StackPanel Orientation="Horizontal"
                Margin="0,16,0,0"
                HorizontalAlignment="Center"
                Spacing="16">
            <Border BorderBrush="{DynamicResource ThemeAccentBrush}" BorderThickness="2" Padding="16" Name="DragMe">
                <TextBlock Name="DragState">Drag Me</TextBlock>
            </Border>
            <Border Background="{DynamicResource ThemeAccentBrush2}" Padding="16"
                    DragDrop.AllowDrop="True">
                <TextBlock Name="DropState">Drop some text or files here</TextBlock>
            </Border>
        </StackPanel>
    </StackPanel>

</Window>

And this is the Code Behind:

using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
using System;
using System.Diagnostics;

namespace DragAndDropTests.Views
{
    public class MainWindow : Window
    {
        private TextBlock _DropState;
        private TextBlock _DragState;
        private Border _DragMe;
        private int DragCount = 0;

        public MainWindow()
        {
            Debug.WriteLine("MainWindow");
            InitializeComponent();
#if DEBUG
            this.AttachDevTools();
#endif
            _DragMe.PointerPressed += DoDrag;

            AddHandler(DragDrop.DropEvent, Drop);
            AddHandler(DragDrop.DragOverEvent, DragOver);
        }

        private async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
        {
            Debug.WriteLine("DoDrag");
            DataObject dragData = new DataObject();
            dragData.Set(DataFormats.Text, $"You have dragged text {++DragCount} times");

            var result = await DragDrop.DoDragDrop(e, dragData, DragDropEffects.Copy);
            switch (result)
            {
                case DragDropEffects.Copy:
                    _DragState.Text = "The text was copied"; break;
                case DragDropEffects.Link:
                    _DragState.Text = "The text was linked"; break;
                case DragDropEffects.None:
                    _DragState.Text = "The drag operation was canceled"; break;
            }
        }

        private void DragOver(object sender, DragEventArgs e)
        {
            Debug.WriteLine("DragOver");
            // Only allow Copy or Link as Drop Operations.
            e.DragEffects = e.DragEffects & (DragDropEffects.Copy | DragDropEffects.Link);

            // Only allow if the dragged data contains text or filenames.
            if (!e.Data.Contains(DataFormats.Text) && !e.Data.Contains(DataFormats.FileNames))
                e.DragEffects = DragDropEffects.None;
        }

        private void Drop(object sender, DragEventArgs e)
        {
            Debug.WriteLine("Drop");
            if (e.Data.Contains(DataFormats.Text))
                _DropState.Text = e.Data.GetText();
            else if (e.Data.Contains(DataFormats.FileNames))
                _DropState.Text = string.Join(Environment.NewLine, e.Data.GetFileNames());
        }

        private void InitializeComponent()
        {
            Debug.WriteLine("InitializeComponent");
            AvaloniaXamlLoader.Load(this);

            _DropState = this.Find<TextBlock>("DropState");
            _DragState = this.Find<TextBlock>("DragState");
            _DragMe = this.Find<Border>("DragMe");
        }
    }
}

Drag & Drop within the application works well in ControlCatalogStandalone and in my application.
The succession of events is DoDrag, DragOver, DragOver, …, Drop in this case.

Dragging a file from Windows Explorer to the ControlCatalogStandalone works well.
The succession of events is DragOver, DragOver, …, Drop

Dragging a file from Windows Explorer to my application doesn't work.
None of the expected events is called here.

What's wrong with my test application?

Zoldan
  • 164
  • 9

0 Answers0