Drag and Drop in MVVM with ScatterView

I am trying to implement drag and drop features in a Surface application that is created using the MVVM pattern. I'm struggling to implement this by sticking to the MVVM pattern. Although I am trying to do this in Surface Application, I think the solution is general enough to apply it to WPF.

I am trying to create the following functions:

  • The user contacts the FrameworkElement element inside the ScatterViewItem to start the drag operation (a certain part of the ScatterViewItem triggers the drag function)
  • When the drag operation begins, a copy of this ScatterViewItem is created and superimposed on the original ScatterViewItem, the copy is what the user drags and ultimately deletes
  • The user can delete the item on another ScatterViewItem (placed in a separate ScatterView).

The overall interaction is very similar to the ShoppingCart application introduced in the Surface SDK, except that the source objects are contained in the ScatterView, and not in the ListBox.

I am not sure how to proceed to ensure the correct connection between my ViewModels to provide this functionality. The main problem that I encountered is the replication of the ScatterViewItem when the user contacts the FrameworkElement.

+6
wpf mvvm drag-and-drop pixelsense
source share
2 answers

You can use the attached property. Create a nested property and in the setproperty method bind to the dropdown event:

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

You can then bind the command in your view model to the corresponding control in the view. Obviously, you might want your attached property to be applied to your specific type of control, rather than to a list.

Hope this helps.

+4
source share

I had a desire to get the idea of โ€‹โ€‹Steve Psaltis. It took some time - custom dependency properties are easily mistaken. It seems to me that SetXXX is the wrong place to send your side effects - WPF should not go, although it does, it can go directly to DependencyObject.SetValue , but PropertyChangedCallback will always be called.

So, here is the full and working code for the custom property:

 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 } } } 

In the XAML markup where you want to use this, you can do, for example.

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

.. And the rest is just to make sure your ViewModel, bindings and command are right.

This version passes IDataObject through a command that seems better to me - you can request it for files or anything in the command. But this is only the current preference, and not an essential characteristic of the answer.

+2
source share

All Articles