Drag and Drop in MVVM with ScatterView
You could use an attached property. Create an attached property and in the setproperty method bind to the droped event :
public static void SetDropCommand(ListView source, ICommand command) { source.Drop += (sender, args) => { var data = args.Data.GetData("FileDrop"); command.Execute(data); }; }
Then you can bind a command in your view model to the relevant control on the view. Obviously you may want to make your attached property apply to your specific control type rather than a listview.
Hope that helps.
I had a go at getting Steve Psaltis's idea working. It took a while - custom dependency properties are easy to get wrong. It looks to me like the SetXXX
is the wrong place to put your side-effects - WPF doesn't have to go though there, it can go directly to DependencyObject.SetValue
, but the PropertyChangedCallback
will always be called.
So, here's complete and working the code for the custom attached 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 e.g.
xmlns:local="clr-namespace:WpfApplication1"...<Button Content="Drop here" Padding="12" AllowDrop="True" local:PropertyHelper.DropCommand="{Binding DropCommand}" />
.. And the rest is just making sure that your ViewModel, bindings and command is right.
This version passes an IDataObject
through to the command which seems better to me - you can query it for files or whatever in the command. But that's just a current preference, not an essential feature of the answer.