Drag and Drop From Editor into own WPF UI

Drag and Drop From Editor into own WPF UI

Neralem
Explorer Explorer
1,301 Views
4 Replies
Message 1 of 5

Drag and Drop From Editor into own WPF UI

Neralem
Explorer
Explorer

Hi,

 

in my ACAD Plugin I want to be able to drag some selected Objects from the Editor into my WPF TreeView which is located in a PaletteSet. In the drop handler i need an array filled with the ObjectId's. I've googled for ages but I've only found snippets to do the opposite.

 

I'm using this great DnD Framework. My first attempt was to just look whats in the data object of the drop handler. It wasn't null - thats great. It was a System.Windows.DataObject and its GetFormats() method returned this list:

 

data.GetFormats()
{string[9]}
[0]: "Embed Source"
[1]: "Object Descriptor"
[2]: "MetaFilePict"
[3]: "Link Source"
[4]: "Link Source Descriptor"
[5]: "Bitmap"
[6]: "System.Drawing.Bitmap"
[7]: "System.Windows.Media.Imaging.BitmapSource"
[8]: "AutoCAD.r22"

 

So I saw the "AutoCAD.r22" format and thought "that must be it!" and called the GetData(string format, bool autoConvert) method of the DataObject: GetData("AutoCAD.r22", true)
and received a MemoryStream. I've created a Byte[] from that and saved it to a file. Then i've looked into the file with a Hex Editor to search for the ObjectId of the Object I've dropped... but no success. In my desperation I've done the same with the other formats - but no luck. At least i can now use the DataObject to determine if the Drop came from the ACAD Editor by checking for  the "AutoCAD.r22" format string.

 

Then I saw the Editor.Dragging and Editor.DragEnded events and thought "ugh, I'm so dumb". The documentation says "Occurs when a dragging operation is performed in a drawing". That must be it!
But it seemed to never fire! My blood pressure starts to grow while I realized that I'm already hours into this "simple task". I've forgot my breakpoint inside the Editor.Dragging event and found out by accident that this event should be called Editor.Jigging because it's raised when a Jig is rendering while you move your Mouse.

 

My third attempt was to assume that, if the drop handler receives a ACAD drop, the dropped objects must be those who are currently selected, right? So... just query the Editor whats selected, right? Easy! ... No its not...
So after asking some kind people here in this Forum, I've learned that i can query the selected Objects by calling Editor.SelectImplied() but this must be inside a Command Method that has the CommandFlags.UsePickSet in its CommandMethod Attribute. So I've created a static method in my UserControl that can be called from this Command to do the ACAD Drop and pass the ObjectID's. In my drop handler i check if the drop came from acad, call the command by Document.SendStringToExecute() and return from my drop handler. But every time my Command was executed, there was nothing selected! And do you want to know why? Because ACAD is deselecting everything in the moment you start the dragging!! At this moment my veins where clearly visible...

So this also wasn't possible.

 

My last and currently woking attempt is to monitor the selected Objects with the Editor.SelectionAdded event and maintain a static List<ObjectId>. This approach doesn't make me happy because thats really dirty and can cause a lot of issues. Is there really no way to do this clean?

0 Likes
Accepted solutions (1)
1,302 Views
4 Replies
Replies (4)
Message 2 of 5

norman.yuan
Mentor
Mentor

The issue you are facing to is that when handling dropping event the event arg's DataObject (IDataObject) does not contains the data in the format of your need (as you know that the data of "AutoCAD.r22" format in the DataObject might has the information you want, but it is in raw bits of MemoryStream, and you have no way to decrypt it into meaningful data.

 

You need to be able to stuff the DataObject with SetData() to get needed data with your own format, so your code can translate it in the receiving/dropping end. It is easy to do when you start dragging from your own coded UI: handing the UI component's MoseMove event, and if the left button is pressed, call e.Data.SetData(...) to get data into it. As you can see, the doing your own UI (winform, or wpf), the UI control gives you the opportunity (MouseMove with left button pressed) to add data into IDataObject for later dropping end to receive. Unfortunately, AutoCAD (i.e. its Editor) does not expose such chance (i.e. an event when mouse is moved with left button pressed) for you to handle (well, AutoCAD itself would do this internally, that is where the "AutoCAD.r22" data comes from), thus, I do not think there is much you can do. 

 

On the other hand, you may just bypass the work of parsing e.DataObject to see what is in the DataObject. Since when you drag whatever entity or entitites, they must be selected. So, in the dropping handler, you can forget e.DataObject, simply use Editor.SelectImplied to obtain all the IDs of selected entities.

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 3 of 5

Neralem
Explorer
Explorer

Hi Norman, thanks for your reply.
Yeah as i said i've tried to get the selected Objects by using the SelectImplied() Method when the drop handler gets called. But at this point there is nothing selected because ACAD is deselecting everything when you start a drag operation.

0 Likes
Message 4 of 5

norman.yuan
Mentor
Mentor
Accepted solution

Well, I did not thought through the deselecting effect as soon as the dragging begins. However, this can be dealt with easily: using Editor.SelectPrevious() instead of SelectImplied(). The point is, when you want to drag one or more entities onto your UI, be it WinForm UI, or WPF UI, you must have the entity or entities selected prior to dragging, right? Hence the SelectPrevious() would gather the selected entities when dragging begins, which deselects the entities, but AutoCAD does save them as Previous selection. 

 

Following video clip shows it works as I expected: I have a modeless WPF form. A listbox is in the middle, which has its "AllowDrop" property set to True. In its Drop event handler, I test the result of Editor.SelectPrevious(); it is returns PromptStatus.OK, I go ahead to grab the ObjectId list and fill the entities' information into the ListBox.

 

 

Obviously, this approach applies both UI of WinForm and WPF. The only thing that does no 100% satisfy me is that the selected entities being dragged do not follow the mouse pointer as ghost image as we see with Jig. But it is just a very minor thing I can live with.
 
HTH
 

Norman Yuan

Drive CAD With Code

EESignature

Message 5 of 5

Neralem
Explorer
Explorer

Thanks so much Norman! This works indeed perfectly. I didnt even need to call Editor.SelectPrevious() inside a command method. It's still a bit hacky but i can't think of a scenario where this wouldn't work.

I can also live with the objects not being dragged visually. Thats okay i think.

 

Thanks a lot!

0 Likes