6

I'm trying to implement drag and drop functionality in a Surface Application that is built using the MVVM pattern. I'm struggling to come up with a means to implement this while adhering to the MVVM pattern. Though I'm trying to do this within a Surface Application I think the solution is general enough to apply to WPF as well.

I'm trying to produce the following functionality:

  • User contacts a FrameworkElement within a ScatterViewItem to begin a drag operation (a specific part of the ScatterViewItem initiates the drag/drop functionality)
  • When the drag operation begins a copy of that ScatterViewItem is created and imposed upon the original ScatterViewItem, the copy is what the user will drag and ultimately drop
  • The user can drop the item onto another ScatterViewItem (placed in a separate ScatterView)

The overall interaction is quite similar to the ShoppingCart application provided in the Surface SDK, except that the source objects are contained within a ScatterView rather than a ListBox.

I'm unsure how to proceeded in order to enable the proper communication between my ViewModels in order to provide this functionality. The main issue I've encountered is replicating the ScatterViewItem when the user contacts the FrameworkElement.

4

2 回答 2

4

您可以使用附加属性。创建一个附加属性并在 setproperty 方法中绑定到删除的事件:


public static void SetDropCommand(ListView source, ICommand command)
        {
            source.Drop += (sender, args) =>
                               {
                                   var data = args.Data.GetData("FileDrop");
                                   command.Execute(data);
                               };
        }

然后,您可以将视图模型中的命令绑定到视图上的相关控件。显然,您可能希望将附加属性应用于您的特定控件类型而不是列表视图。

希望有帮助。

于 2009-09-03T19:52:12.423 回答
2

我尝试让 Steve Psaltis 的想法奏效。花了一段时间 - 自定义依赖属性很容易出错。在我看来,SetXXX放置副作用的地方是错误的 - WPF 不必去那里,它可以直接去DependencyObject.SetValue,但PropertyChangedCallback总是会被调用。

因此,这里是自定义附加属性的完整代码:

using System.Windows;
using System.Windows.Input;

namespace WpfApplication1
{
    public static class PropertyHelper
    {
        public static readonly DependencyProperty DropCommandProperty = DependencyProperty.RegisterAttached(
            "DropCommand",
            typeof(ICommand),
            typeof(PropertyHelper),
            new PropertyMetadata(null, OnDropCommandChange));

        public static void SetDropCommand(DependencyObject source, ICommand value)
        {
            source.SetValue(DropCommandProperty, value);
        }

        public static ICommand GetDropCommand(DependencyObject source)
        {
            return (ICommand)source.GetValue(DropCommandProperty);
        }

        private static void OnDropCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ICommand command = e.NewValue as ICommand;
            UIElement uiElement = d as UIElement;
            if (command != null && uiElement != null)
            {
                uiElement.Drop += (sender, args) => command.Execute(args.Data);
            }

            // todo: if e.OldValue is not null, detatch the handler that references it
        }
    }
}

在要使用它的 XAML 标记中,您可以执行例如

xmlns:local="clr-namespace:WpfApplication1"
...
<Button Content="Drop here" Padding="12" AllowDrop="True"
   local:PropertyHelper.DropCommand="{Binding DropCommand}" />

.. 剩下的就是确保您的 ViewModel、绑定和命令是正确的。

这个版本通过IDataObject对我来说似乎更好的命令 - 您可以在命令中查询文件或任何内容。但这只是当前的偏好,而不是答案的基本特征。

于 2011-01-28T16:03:27.940 回答