使用 VirtualFileDataObject 在 WPF 中实现虚拟文件放置

Implementing Virtual File Drop in WPF using VirtualFileDataObject

我正在使用这个项目的解决方案:http://dlaa.me/blog/post/9913083#comment-2930777923

我想让我的 WPF 程序能够处理放入其中的虚拟文件,但我无法从 MemoryStream 读取相关数据,我从 DragEventArgs e.Data.GetData() 接收到的数据。

我读了很多帖子。最接近的是:

但它们都只处理从我的应用程序到文件系统的情况。

没有任何花哨的 mvvm 东西...

我没有进一步了解的地方是

private void Label_Drop(object sender, DragEventArgs e){...}

方法在我后面的代码中:

using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Input;
using Delay;
using System.Runtime.Serialization.Formatters.Binary;

namespace VirtualFileDataObjectDemo
{
    public partial class Window1 : Window
    {
        private static TextWriterTraceListener traceListener;
        private string logPath;
        private string filePath;

        // From Windows SDK header files
        private const string CFSTR_INETURLA = "UniformResourceLocator";

        public Window1()
        {
            //logPath = Path.Combine(@"d:\Temp", @"Log\TextWriterOutput.log");
            logPath = Path.Combine(Directory.GetCurrentDirectory(), @"Log\TextWriterOutput.log");
            filePath = Path.Combine(Directory.GetCurrentDirectory(), @"Log");
            traceListener = new TextWriterTraceListener(logPath, "traceListener");

            InitializeComponent();

            // Attach to interesting events
            Text.MouseLeftButtonDown += new MouseButtonEventHandler(Text_MouseButtonDown);
            Text.MouseRightButtonDown += new MouseButtonEventHandler(Text_MouseButtonDown);
            TextUrl.MouseLeftButtonDown += new MouseButtonEventHandler(TextUrl_MouseButtonDown);
            TextUrl.MouseRightButtonDown += new MouseButtonEventHandler(TextUrl_MouseButtonDown);
            VirtualFile.MouseLeftButtonDown += new MouseButtonEventHandler(VirtualFile_MouseButtonDown);
            VirtualFile.MouseRightButtonDown += new MouseButtonEventHandler(VirtualFile_MouseButtonDown);
            MoreVirtualFiles.MouseLeftButtonDown += new MouseButtonEventHandler(TextUrlVirtualFile_MouseButtonDown);
            MoreVirtualFiles.MouseRightButtonDown += new MouseButtonEventHandler(TextUrlVirtualFile_MouseButtonDown);
        }

        private void Text_MouseButtonDown(object sender, MouseButtonEventArgs e) //TEXT
        {
            var virtualFileDataObject = new VirtualFileDataObject();

            // Provide simple text (in the form of a NULL-terminated ANSI string)
            virtualFileDataObject.SetData(
                (short)(DataFormats.GetDataFormat(DataFormats.Text).Id),
                Encoding.Default.GetBytes("This is some sample text[=11=]"));

            DoDragDropOrClipboardSetDataObject(e.ChangedButton, Text, virtualFileDataObject, DragDropEffects.Copy);
        }

        private void TextUrl_MouseButtonDown(object sender, MouseButtonEventArgs e) //WEBADDRESS
        {
            var virtualFileDataObject = new VirtualFileDataObject();

            // Provide simple text and an URL in priority order
            // (both in the form of a NULL-terminated ANSI string)
            virtualFileDataObject.SetData(
                (short)(DataFormats.GetDataFormat(CFSTR_INETURLA).Id),
                Encoding.Default.GetBytes("http://blogs.msdn.com/delay/[=11=]"));
            virtualFileDataObject.SetData(
                (short)(DataFormats.GetDataFormat(DataFormats.Text).Id),
                Encoding.Default.GetBytes("http://blogs.msdn.com/delay/[=11=]"));

            DoDragDropOrClipboardSetDataObject(e.ChangedButton, TextUrl, virtualFileDataObject, DragDropEffects.Copy);
        }

        private void VirtualFile_MouseButtonDown(object sender, MouseButtonEventArgs e) //VIRTUALFILE
        {
            var virtualFileDataObject = new VirtualFileDataObject(
                null,
                (vfdo) =>
                {
                    if (DragDropEffects.Move == vfdo.PerformedDropEffect)
                    {
                        // Hide the element that was moved (or cut)
                        // BeginInvoke ensures UI operations happen on the right thread
                        Dispatcher.BeginInvoke((Action)(() => VirtualFile.Visibility = Visibility.Hidden));
                    }
                });

            // Provide a virtual file (generated on demand) containing the letters 'a'-'z'
            virtualFileDataObject.SetData(new VirtualFileDataObject.FileDescriptor[]
            {
                new VirtualFileDataObject.FileDescriptor
                {
                    Name = "Alphabet.txt",
                    Length = 26,
                    ChangeTimeUtc = DateTime.Now.AddDays(-1),
                    StreamContents = stream =>
                        {
                            var contents = Enumerable.Range('a', 26).Select(i => (byte)i).ToArray();
                            stream.Write(contents, 0, contents.Length);
                        }
                },
            });

            DoDragDropOrClipboardSetDataObject(e.ChangedButton, TextUrl, virtualFileDataObject, DragDropEffects.Move | DragDropEffects.Copy);
        }

        private void TextUrlVirtualFile_MouseButtonDown(object sender, MouseButtonEventArgs e) //ALL THREE TOGETHER
        {
            var virtualFileDataObject = new VirtualFileDataObject(
                  // BeginInvoke ensures UI operations happen on the right thread
                  (vfdo) => Dispatcher.BeginInvoke((Action)(() => BusyScreen.Visibility = Visibility.Visible)),
                  (vfdo) => Dispatcher.BeginInvoke((Action)(() => BusyScreen.Visibility = Visibility.Collapsed)));


            virtualFileDataObject.SetData(new VirtualFileDataObject.FileDescriptor[]
            {
                new VirtualFileDataObject.FileDescriptor
                {
                    Name = "Example.xml",
                    StreamContents = stream =>
                        {
                            using(var webClient = new WebClient())
                            {
                                var data = webClient.DownloadData("https://www.w3schools.com/xml/note.xml");
                                stream.Write(data, 0, data.Length);
                            }
                        }
                },
                new VirtualFileDataObject.FileDescriptor
                {
                    Name = "Example2.xml",
                    StreamContents = stream =>
                        {
                            using(var webClient = new WebClient())
                            {
                                var data = webClient.DownloadData("https://www.w3schools.com/xml/cd_catalog.xml");
                                stream.Write(data, 0, data.Length);
                            }
                        }
                },

                new VirtualFileDataObject.FileDescriptor
                {
                    Name = "Example3.xml",
                    StreamContents = stream =>
                        {
                            using(var webClient = new WebClient())
                            {
                                var data = webClient.DownloadData("https://www.w3schools.com/xml/plant_catalog.xml");
                                stream.Write(data, 0, data.Length);
                            }
                        }
                },
            });

            DoDragDropOrClipboardSetDataObject(e.ChangedButton, MoreVirtualFiles, virtualFileDataObject, DragDropEffects.Move | DragDropEffects.Copy);
        }

        private static void DoDragDropOrClipboardSetDataObject(MouseButton button, DependencyObject dragSource, VirtualFileDataObject virtualFileDataObject, DragDropEffects allowedEffects)
        {
            try
            {
                if (button == MouseButton.Left)
                {
                    // Left button is used to start a drag/drop operation
                    VirtualFileDataObject.DoDragDrop(dragSource, virtualFileDataObject, allowedEffects);
                }
                else if (button == MouseButton.Right)
                {
                    // Right button is used to copy to the clipboard
                    // Communicate the preferred behavior to the destination
                    virtualFileDataObject.PreferredDropEffect = allowedEffects;
                    Clipboard.SetDataObject(virtualFileDataObject);

                }
            }
            catch (COMException ce)
            {
                traceListener.WriteLine("COM Exception");
                traceListener.WriteLine(ce);
                traceListener.WriteLine(ce.Message);
                traceListener.WriteLine(ce.InnerException);

                // Failure; no way to recover
            }
        }

        private void Label_Drop(object sender, DragEventArgs e)
        {
            try
            {
            dropLabel.Content = "";
            string[] retrievedFormats = e.Data.GetFormats();
            foreach (string retFormat in retrievedFormats)
            {
                object retrievedData = e.Data.GetData(retFormat);
                dropLabel.Content = dropLabel.Content + Environment.NewLine + retrievedData.ToString() + " - " + retFormat;
            }

        }
            catch (Exception ex)
            {
                traceListener.WriteLine("-------------");
                traceListener.WriteLine(ex + Environment.NewLine);
                traceListener.WriteLine(ex.Message + Environment.NewLine);
                traceListener.WriteLine(ex.StackTrace + Environment.NewLine);
                traceListener.WriteLine("-------------");
                traceListener.Flush();
            }
}


        private void Label_DragEnter(object sender, DragEventArgs e)
        {
            e.Effects = DragDropEffects.Copy;
        }
    }
}

和 XAML:

<Window x:Class="VirtualFileDataObjectDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="VirtualFileDataObjectDemo"
    Height="800"
    Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <UniformGrid
            Rows="5"
            Background="#ffdddddd"
            TextElement.FontSize="22"
            TextElement.FontWeight="Bold">

            <UniformGrid.Resources>
                <Style TargetType="{x:Type Label}">
                    <Setter Property="Background" Value="Orange"/>
                    <Setter Property="Foreground" Value="White"/>
                    <Setter Property="BorderBrush" Value="Black"/>
                    <Setter Property="BorderThickness" Value="1"/>
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                    <Setter Property="VerticalContentAlignment" Value="Center"/>
                    <Setter Property="Margin" Value="10"/>
                </Style>
            </UniformGrid.Resources>

            <ContentControl
                Content="Drag an item or right-click to copy it:"
                FontSize="18"
                VerticalAlignment="Center"
                Margin="20"/>
            <Label
                x:Name="Text"
                Content="Text only"/>
            <Label
                x:Name="TextUrl"
                Content="Text and URL"/>
            <Label
                x:Name="VirtualFile">
                <DockPanel>
                    <ContentControl
                        Content="Virtual file"
                        DockPanel.Dock="Left"
                        VerticalAlignment="Center"/>
                    <ContentControl
                        Content="[Drag moves; paste cuts]"
                        FontSize="14"
                        HorizontalAlignment="Right"
                        VerticalAlignment="Center"/>
                </DockPanel>
            </Label>
            <Label
                x:Name="MoreVirtualFiles"
                Content="More virtual files"/>
        </UniformGrid>

        <Grid
            x:Name="BusyScreen"
            Background="LightGray"
            Visibility="Collapsed">
            <StackPanel
                VerticalAlignment="Center"
                Margin="50">
                <Viewbox>
                    <TextBlock Text="Busy..."/>
                </Viewbox>
                <ProgressBar IsIndeterminate="True" Height="20"/>
            </StackPanel>
        </Grid>
        <Label Name="dropLabel" Grid.Row="1" Content="Drop Area" MinHeight="50" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" FontSize="20" AllowDrop="True" Drop="Label_Drop" DragEnter="Label_DragEnter"/>
    </Grid>
</Window>

VirtualFileDataObject 可以从这里下载: http://dlaa.me/Samples/VirtualFileDataObjectDemo/VirtualFileDataObjectDemo.zip

感谢 James Barrass。 他在此主题中的解决方案:

Dropped zip file causes e.Data.GetData("FileContents") to throw an exception

解决了我的问题。