【问题标题】:Drag Drop for Files AND also Folders拖放文件和文件夹
【发布时间】:2014-01-27 11:42:30
【问题描述】:

所以我之前看过这个链接:

http://blogs.msdn.com/b/delay/archive/2009/10/26/creating-something-from-nothing-developer-friendly-virtual-file-implementation-for-net.aspx

该类可以完美地用于文件,但它不支持目录等,有没有人知道如何更改该类以支持它,我不是 pinvoke 高手。我尝试了一百万种不同的东西,覆盖一些代码以将我的放置源的文件复制和目录创建到 TEMP 目录并尝试触发 FileDrop,但这会完全锁定应用程序。

这让我相信必须有更好的方法来创建目录结构。

【问题讨论】:

  • 我已经尝试了一百万种不同的东西...请给我们看一些。
  • 您能展示一下您是如何创建FILEGROUPDESCRIPTOR 结构的吗?

标签: wpf winapi drag-and-drop


【解决方案1】:

拖放操作的主要部分是DragDrop.DoDragDrop 方法。来自 MSDN 上的DragDrop.DoDragDrop Method 页面:

public static DragDropEffects DoDragDrop(
    DependencyObject dragSource,
    Object data,
    DragDropEffects allowedEffects
)

特别感兴趣的是data 参数:

包含被拖动数据的数据对象。

注意这个参数的类型是Object,所以完全由你决定你在操作中使用什么对象。现在我不确定你从链接到的页面中找到了什么代码,但如果我试图拖放文件和文件夹,我不需要特殊的类来为我做这件事。

最简单的方法是只传递文件和/或文件夹路径而不是实际数据。放置数据的控件可以使用文件路径访问数据,就像拖动源一样容易。您应该能够从您的代码中找到DragDrop.DoDragDrop 方法并轻松地修改该代码。

如果您想以正确的方式进行拖放操作,那么我建议您查看 MSDN 上的 Drag and Drop Overview 页面。它充分解释了要做什么,并提供了几个代码示例。

【讨论】:

  • 我认为操作正在做一些放置目标不是 wpf 控件的事情。他想将 wpf 应用程序 拖出 并将其放入 com 组件中;这只是一个猜测。如果它是正确的猜测,你需要改变你的答案。这是一个很好的答案,但对于一个不同的问题:)
  • 你可能是对的......这就是用户添加链接但没有讨论他们在问题中链接到什么的问题。我想我会留下答案,因为它可能会帮助有类似拖放问题的人。
  • 是的,问题本身需要澄清。我会以与您相同的精神添加另一个答案。
【解决方案2】:

在没有太多WPF经验的情况下在MVVM中实现拖拽,可以参考5个步骤;我将概述这些...

第 1 步:附加行为

为您的项目添加一个名为 Behaviours 的新类。它应该看起来像这样......

public static class Behaviours
{
    #region DandBehaviour
    public static readonly DependencyProperty DandBehaviourProperty =
        DependencyProperty.RegisterAttached("DandBehaviour", typeof(ICommand), typeof(Behaviours),
            new FrameworkPropertyMetadata(null,
                FrameworkPropertyMetadataOptions.None,
                OnDandBehaviourChanged));
    public static ICommand GetDandBehaviour(DependencyObject d)
    {
        return (ICommand)d.GetValue(DandBehaviourProperty);
    }
    public static void SetDandBehaviour(DependencyObject d, ICommand value)
    {
        d.SetValue(DandBehaviourProperty, value);
    }
    private static void OnDandBehaviourChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Grid g = d as Grid;
        if (g != null)
        {
            g.Drop += (s, a) =>
                {
                    ICommand iCommand = GetDandBehaviour(d);
                    if (iCommand != null)
                    {
                        if (iCommand.CanExecute(a.Data))
                        {
                            iCommand.Execute(a.Data);
                        }
                    }
                };
        }
        else
        {
            throw new ApplicationException("Non grid");
        }
    }
    #endregion
}

这个类实现了一个附加的依赖属性,可以从你的 Xaml 和你的视图模型中访问。它挂钩“Drop”事件并在其上调用命令。

第 2 步:检测 Xaml

在此步骤中,您需要将名称空间添加到 Xaml,以便它可以找到步骤 1 中的行为类。它看起来像这样...

xmlns:b="clr-namespace:DdMvvm"

此语句将别名“b”分配给行为。然后你告诉 WPF 根窗口接受 drop...

AllowDrop="true"

然后您可以将行为添加到您的逻辑树中......

<Grid AllowDrop="True" b:Behaviours.DandBehaviour="{Binding DandCommand}">
    <DockPanel Background="Bisque" AllowDrop="True"/>
</Grid>

第 3 步:添加命令支持

从http://msdn.microsoft.com/en-us/magazine/dd419663.aspx 下载 Josh Smith 的“中继命令”为了完整起见,这里给出...

public class RelayCommand : ICommand
{   //http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }
    public bool CanExecute(object parameter)
    {
        return _canExecute(parameter);
    }
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }
    public void Execute(object parameter)
    {
        _execute(parameter);
    }
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;
}

第 4 步:编写视图模型

一个视图模型看起来像这样......

public class ViewModel : INotifyPropertyChanged
{
    public ICommand DandCommand { get; set; }
    public ViewModel()
    {
        DandCommand = new RelayCommand(ExecuteDandCommand, CanExecuteDandCommand);
    }
    private void ExecuteDandCommand(object obj)
    {
        if (obj != null)
        {
            IDataObject ido = obj as IDataObject;
            if (ido != null)
            {
                var fileDrop = ido.GetData(DataFormats.FileDrop, true);
                var filesOrDirectories = fileDrop as String[];
                if (filesOrDirectories != null && filesOrDirectories.Length > 0)
                {
                    foreach (string fullPath in filesOrDirectories)
                    {
                        if (Directory.Exists(fullPath))
                        {
                            Console.WriteLine(@"{0} is a directory", fullPath);
                        }
                        else if (File.Exists(fullPath))
                        {
                            Console.WriteLine(@"{0} is a file", fullPath);
                        }
                        else
                        {
                            Console.WriteLine(@"{0} is not a file and not a directory", fullPath);
                        }
                    }
                }
            }
        }
    }
    private bool CanExecuteDandCommand(object obj)
    {
        return true;
    }
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion

}

此 VM 实现了一个命令(称为 DandCommand),该命令将被附加行为触发(还记得第 1 步吗?)。 VM 的“多汁部分”是取消引用拖放有效负载的位。在这个特定的 VM 中,代码取消引用数据并确定它是文件还是目录。然后它将诊断信息打印到控制台。您可以更改此部分以加载图像、互联网链接或任何可以删除的内容。

第 5 步:连接数据上下文

这是由不同的开发人员以不同的方式完成的(对于工业应用程序,很多人喜欢使用 Prism 和 Unity,但对于这篇文章的简单操作方法来说,这并不重要)。最直接的方法是将您的视图更改为如下所示...

public MainWindow()
{
    InitializeComponent();
    DataContext = new ViewModel();
}

此代码将窗口的数据上下文设置为您的 VM,以便可以进行绑定。

这些步骤为您提供了 MVVM 和拖放操作的良好起点,并让整个工作正常进行。将 MVVM 用于这些事情的最大回报是您获得的干净分离和划分。即,可以对 VM 进行单元测试,而无需实例化 WPF 绑定引擎。

【讨论】:

    猜你喜欢
    • 2012-11-10
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 2020-02-10
    • 1970-01-01
    • 2022-12-20
    • 1970-01-01
    • 2011-09-06
    相关资源
    最近更新 更多