A couple of days ago I had to create an application that should support drag and drop files from Windows Explorer to my WPF ListView. As I was using MVVM and the Drop event doesn’t have a Command property I had to implement this using Attached Behaviors. My attached behavior enable me to set a Command in the XAML that would execute when the drop event occurs.
Here is the code:
public static class ListViewBehavior { public static ICommand GetPreviewDropCommand(UIElement obj) { return (ICommand)obj.GetValue(PreviewDropCommandProperty); } public static void SetPreviewDropCommand(UIElement obj, ICommand command) { obj.SetValue(PreviewDropCommandProperty, command); obj.Drop += (sender, e1) => { string[] array = e1.Data.GetData(DataFormats.FileDrop) as string[]; if (array != null) { command.Execute(array); } e1.Handled = true; }; } public static readonly DependencyProperty PreviewDropCommandProperty = DependencyProperty.RegisterAttached ( "PreviewDropCommand", typeof(ICommand), typeof(ListViewBehavior) ); } |
Then I set the attached behavior to the ListView in the XAML setting the command I wanted to execute from the ViewModel (the Command is exposed in the ViewModel as a property):
<listview Grid.Row="1" Grid.ColumnSpan="3" ItemsSource="{Binding FilesToConvert}" Margin="2" AllowDrop="True" behaviors:ListViewBehavior.PreviewDropCommand="{Binding DropFilesCommand}"> ... </listview> |
When I run this, I got the surprise that the SetPreviewDropCommand was never called. I made some research and found out that when you set an attached property from the XAML WPF doesn’t call the setter SetXXX for the DependencyProperty, it sets the value directly to the property system without using the SetValue.
So to sort out this problem we need to move our logic to the OnXXXChanged defined in the PropertyMetadata that will be called every time the SetPreviewDropCommand is called. The resulting code should be:
public static ICommand GetPreviewDropCommand(UIElement obj) { return (ICommand)obj.GetValue(PreviewDropCommandProperty); } public static void SetPreviewDropCommand(UIElement obj, ICommand command) { obj.SetValue(PreviewDropCommandProperty, command); } public static readonly DependencyProperty PreviewDropCommandProperty = DependencyProperty.RegisterAttached ( "PreviewDropCommand", typeof(ICommand), typeof(ListViewBehavior), new PropertyMetadata(OnCommandChanged) ); private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement obj = d as UIElement; ICommand command = GetPreviewDropCommand(obj); obj.Drop += (sender, e1) => { string[] array = e1.Data.GetData(DataFormats.FileDrop) as string[]; if (array != null) { command.Execute(array); } e1.Handled = true; }; } |
Now it works!
Tags: Attached Behaviors, Dependency Properties, MVVM, WPF
WoW Adult…
[...]Attached Behaviors – WPF MVVM « .:: Beno’s Blog ::.[...]…