使用ScatterView在MVVM中拖放

时间:2009-06-23 18:42:38

标签: wpf mvvm drag-and-drop pixelsense

我正在尝试在使用MVVM模式构建的Surface应用程序中实现拖放功能。我在努力想出一种在坚持MVVM模式的同时实现这一目标的方法。虽然我试图在Surface应用程序中执行此操作,但我认为该解决方案通用性足以应用于WPF。

我正在尝试生成以下功能:

  • 用户联系ScatterViewItem中的FrameworkElement以开始拖动操作(ScatterViewItem的特定部分启动拖放功能)
  • 当拖动操作开始时,会创建该ScatterViewItem的副本并将其强加于原始ScatterViewItem,该副本将是用户将拖动并最终删除的内容
  • 用户可以将项目放到另一个ScatterViewItem(放在单独的ScatterView中)

整体交互非常类似于Surface SDK中提供的ShoppingCart应用程序,除了源对象包含在ScatterView而不是ListBox中。

我不确定如何继续以便在我的ViewModel之间进行正确的通信以提供此功能。我遇到的主要问题是当用户联系FrameworkElement时复制ScatterViewItem。

2 个答案:

答案 0 :(得分:4)

您可以使用附加财产。创建附加属性,并在setproperty方法中绑定到droped事件:


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

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

希望有所帮助。

答案 1 :(得分: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传递给命令,这对我来说似乎更好 - 您可以在命令中查询文件或其他内容。但这只是当前的偏好,而不是答案的基本特征。