拖放文件和文件夹

时间:2014-01-27 11:42:31

标签: wpf winapi drag-and-drop

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

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

这个类对于Files是完美无缺的,但它不支持目录等,有没有人知道我怎么能改变它来支持它,我没有pinvoke高手。我已经尝试了一百万种不同的东西,重写一些代码,将我的drop source文件复制和目录创建到TEMP目录并尝试触发FileDrop,但这会完全锁定应用程序。

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

2 个答案:

答案 0 :(得分:0)

拖放操作的主要部分是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页面。它完全解释了要做什么,并提供了几个代码示例。

答案 1 :(得分:0)

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

第1步:附加行为

在项目中添加一个名为Behaviors的新类。看起来应该是这样......

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和View Model中访问它。它挂钩“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的'Relay Command'为了完整起见,这里给出了......

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绑定引擎。