Drag & Drop into a DockPane

803
10
05-17-2019 12:41 AM
AlexWieschmann2
New Contributor II

Hello,

does anyone have a working example to drag a FeatureClass into a textbox on a DockPane so that the path appears in the textbox? The only drag and drop example is an Excel example that does not address a DockPane.

And in the documentation, a parameter of type DropData should be specified for the OnDrop function. Here, however, only a DropInfo object is possible ...?

public override void OnDrop(DropData dropInfo)     {       foreach (var item in dropInfo.Items)       {         if (System.IO.Path.GetExtension(item.Data as string) == ".aprx")           item.Handled = true;       }     } 

And with the DropInfo object I get neither a reference to the text box, nor to the FeatureClass.

Thank you

Alex

0 Kudos
10 Replies
UmaHarano
Esri Regular Contributor

Hi Alex,

Dockpanes support drag drop.  This wiki page helps you implement drag and drop to dockpanes and to specific controls as such text boxes on the pane.  ProGuide: DockPanes - Support drag and drop

Additionally, in your OnDrop override, here is the code snippet to use to access the  feature class item being dropped:

public override void OnDrop(DropInfo dropInfo)
   {
      //eg, if you are accessing a dropped file
      string filePath = dropInfo.Items[0].Data.ToString();
      string path = "";
      if (dropInfo.Data is List<ClipboardItem> clipboardItems)
        {             
           var thisItem = clipboardItems.FirstOrDefault();
           path = thisItem.ItemInfoValue.catalogPath; //Use this at 2.3. Add reference to Esri.ArcGIS.ItemIndex.dll found in the bin folder of Pro installation location
           path = thisItem.CatalogPath; //At 2.4 use this instead.
           ArcGIS.Desktop.Framework.Dialogs.MessageBox.Show($"Dropped {path} from Catalog");
       }
       //set to true if you handled the drop
       dropInfo.Handled = true;
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Thanks

Uma

0 Kudos
AlexWieschmann2
New Contributor II

Unfortunately, when calling the ItemInfoValue method, the error occurs:

Method not found: ESRI.ArcGIS.ItemIndex.ItemInfoValue
ArcGIS.Desktop.Core.ClipboardItem.get_ItemInfoValue()

0 Kudos
UmaHarano
Esri Regular Contributor

Hi Alex,

When you add the reference to Esri.ArcGIS.ItemIndex.dll, the Copy Local attribute needs to be set to "False". This will fix the issue you are experiencing.

Note: As a precaution, after you change this attribute, clean up your AssemblyCache folder in this location - C:\Users\UserName\AppData\Local\ESRI\ArcGISPro\AssemblyCache (One time only after this setting change).

Thanks

Uma

0 Kudos
AlexWieschmann2
New Contributor II

Thank you! One last question. How can I get a reference to the controls (DataGrid, TextBox ...)? The TargetItem and VisualTargetItem Object return only null values.

Alex

0 Kudos
UmaHarano
Esri Regular Contributor

Hi Alex,

If you set the Dockpane's "isDropTarget" attribute to false, then when you drag and drop into a control like the text box, you can get a handle to it using the `dropInfo.VisualTarget` property.

My config.daml for dockpane: (Note the isDropTarget is set to false)

<dockPane id="DockpaneDragDrop_DragDropDockpane" ... isDropTarget="false">
 <content className="DragDropDockpaneView" />
 </dockPane>‍‍‍‍‍‍

xaml for dockpane:

     <UserControl.Resources>
        <ResourceDictionary>           
            <Style x:Key="FeatureClassTextBox" TargetType="{x:Type TextBox}">
                <Setter Property="dragDrop:DragDrop.IsDragSource" Value="True" />
                <Setter Property="dragDrop:DragDrop.IsDropTarget" Value="True" />
                <Setter Property="dragDrop:DragDrop.DropHandler" Value="{Binding}" />
                <Setter Property="dragDrop:DragDrop.DragHandler" Value="{Binding}" />
            </Style>
        </ResourceDictionary>
       
    </UserControl.Resources>
...


<TextBox Width="250" Text="{Binding FeatureLayer}" Style="{StaticResource FeatureClassTextBox}"></TextBox>

In your OnDrop callback:

public override void OnDrop(DropInfo dropInfo)
        {
           ...
            var myTextBox = dropInfo.VisualTarget //{System.Windows.Controls.TextBox};
            ...
            dropInfo.Handled = true;

        }

Thanks

Uma

0 Kudos
AlexWieschmann2
New Contributor II

Ok, another last question ;)

When I try to drag a layer from the Contents Pane to a DockPane, I only get an ArcGIS.Desktop.Internal.Mapping.TOC.TOCDragPayload object that unfortunately can not be accessed?!
 
In the help I find only examples of the Catalog Pane and Windows Explorer ...

Thanks

Alex

0 Kudos
UmaHarano
Esri Regular Contributor

Hi

Dragging from Contents pane is not yet supported using the public API. It will be available with 2.5 that is scheduled to be released in Jan 2020.  In the meantime, the code below will work but it uses some internal namespaces.

Extension methods:

using ArcGIS.Desktop.Framework.DragDrop;
using ArcGIS.Desktop.Internal.Mapping.TOC;//note the “Internal”
using ArcGIS.Desktop.Mapping;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace DragAndDrop.Helpers
{
  public static class DragDropExtensions
  {
 
    public static bool HasTOCContent(this DropInfo dropInfo)
    {
      return dropInfo?.Data is TOCDragPayload; //This class is in an internal namespace
    }
 
    public static List<MapMember> GetTOCContent(this DropInfo dropInfo)
    {
      if (!HasTOCContent(dropInfo))
        return new List<MapMember>();
      var tocPayload = dropInfo.Data as TOCDragPayload;
      //get the content
      return tocPayload.ViewModels.Select(vm => vm.Model).OfType<MapMember>()?.ToList() ?? new List<MapMember>();
    }
 
    public static List<T> GetTOCContentOfType<T>(this DropInfo dropInfo) where T: MapMember
    {
      return GetTOCContent(dropInfo).OfType<T>()?.ToList() ?? new List<T>();      
    }
 
    public static string GetMapUri(this DropInfo dropInfo)
    {
      return HasTOCContent(dropInfo) ? ((TOCDragPayload)dropInfo.Data).SourceMapURI : string.Empty;
    }
  }
}

Usage:

public override async void OnDrop(DropInfo dropInfo)
    {
      if (dropInfo.HasTOCContent())//extension method
      {
        var mm = dropInfo.GetTOCContent();//extension method - returns all MapMembers being dropped
        //get just feature layers, for example
        var layers = dropInfo.GetTOCContentOfType<FeatureLayer>(); //extension method
 
        //which, honestly, is the same as doing this...so take your pick...
        var layers2 = mm.OfType<FeatureLayer>()?.ToList() ?? new List<FeatureLayer>();
        //and then ditto for StandaloneTable, ElevationSurface, LabelClass, etc.
 
        //last, get the source map to which the map members belong
        var mapuri = dropInfo.GetMapUri();
        //99 times out of a 100 this will be the active view map....
        //but, if not, get the actual map (or scene) this way
        var map = FrameworkApplication.Panes.OfType<IMapPane>()?.Select(mp => mp.MapView.Map)
                       .Where(m => m.URI == mapuri).First();
      }

Thanks

Uma

0 Kudos
AlexWieschmann2
New Contributor II

Dear Uma,

is there maybe an example for the TOCDragData interface?

Thanks

Alex

0 Kudos
UmaHarano
Esri Regular Contributor

Hi Alex,

I have attached a modified DragAndDrop sample that shows you how to drag and drop content from the Map's TOC.

To use the sample:

1. From the Add-In tab, click the Drag and Drop TOC Items button. A dockpane with a text box will show up.
2. Drag any layer(s) from the active map's TOC into the dockpane's text box..
3. The text box in the dockpane will list information about the map members being dragged and dropped.

Thanks

Uma