Drag & drop in WPF part2 ...
Last part, we focused on the drag... In this part we will focus on drop (which is relatively straight forward) ...
DropTargets must set AllowDrop = true
It all begins with a Visual Element setting its AllowDrop to true; this tells the D&D subsystem your control is a drop target ... You can do this in XAML or in code..
DragEnter, DragOver, DragLeave
I hardly ever subscribe to any of these events.. but let's walk through the niceties on each ..
- DragEnter -- happens when cursor/mouse enters; useful for things like "highlighting" the target by showing an adorner, or similar ... You would think that when mouseEnter, you can query the dataobject and provide feedback on whether the drop would be allowed... Well, you can, but it is pretty useless. Dragover can override that, so the place to handle the feedback is on DragOver..
- DragLeave -- happens when cursor leaves.. Here you should undo any thing you did on DragEnter ..
- Dragover -- here you can provide feedback to whether the drop would succeed ..
Walking through the Drop code with an example:
From our previous work in progress project, I replaced old DropTarget StackPanel with a DropTargetText and DropTargetImages ...
DropTargetImages will handle DragOver,DragEnter, Dragleave to check if dataObject type is Images and if not, it will set e.Effects to None, and provide some ugly feedback..
DropTargetText will handle Dragover and Drop (since our old dataobject type is Text)
void Window1_Loaded(object sender, RoutedEventArgs e) { this.DragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown); this.DragSource.PreviewMouseMove += new MouseEventHandler(DragSource_PreviewMouseMove); // DROP this.DropTargetImages.DragEnter += new DragEventHandler(DropTargetImages_DragEnter); this.DropTargetImages.DragLeave += new DragEventHandler(DropTargetImages_DragLeave); this.DropTargetImages.DragOver += new DragEventHandler(DropTargetImages_DragOver); this.DropTargetText.DragOver += new DragEventHandler(DropTargetText_DragOver); this.DropTargetText.Drop += new DragEventHandler(DropTargetText_Drop); } void DropTargetText_Drop(object sender, DragEventArgs e) { IDataObject data = e.Data; if (data.GetDataPresent(DataFormats.Text)) { MessageBox.Show( string.Format("right format, thanks for dropping '{0}'" , ((string)data.GetData(DataFormats.Text)))); } } void DropTargetImages_DragOver(object sender, DragEventArgs e) { if (!e.Data.GetDataPresent("Images")) { e.Effects = DragDropEffects.None; e.Handled = true; } } void DropTargetText_DragOver(object sender, DragEventArgs e) { if (!e.Data.GetDataPresent("Text")) { e.Effects = DragDropEffects.None; e.Handled = true; } } void DropTargetImages_DragLeave(object sender, DragEventArgs e) { RunStoryboard("Timeline2"); } void RunStoryboard(string name) { Storyboard sb = this.FindResource(name) as Storyboard ; System.Diagnostics.Debug.Assert(sb != null); sb.Begin(DropTargetImages); } void DropTargetImages_DragEnter(object sender, DragEventArgs e) { if (!e.Data.GetDataPresent("Image")) { RunStoryboard("Timeline1"); e.Effects = DragDropEffects.None; e.Handled = true; } } |
The source code for snippet above is here.
Handling the Drop can be that straight forward, but it almost never is that simple..
In Part3, I can walk through much more samples of handling drop ...