7

I am creating a Word Add-In and in order to allow dragging something from a custom task pane to the document, I have followed the following guide: http://msdn.microsoft.com/en-us/library/office/hh780901(v=office.14).aspx

There are some real drawbacks using this approach.

First, the transparent Windows Form (or WPF in my case) that catches the drop event is the size of the Window, not the document, and RangeFromPoint always returns a value, even if we aren't over the document (for instance, if we are over the Ribbon). So once you drag something and this form is created, no matter where you drop, it will be placed in the document. There is no graceful way to cancel once you've started.

My question is:

Has anyone done any work with Drag and Drop in a Word Add In, and found a better way to handle it than the supplied example by Microsoft?

It would be nice to either use the current solution, but know when the user is not dragging over the document or have that transparent window only show over the document area.

Kris Adams
  • 680
  • 6
  • 11

1 Answers1

2

Hope you already had your answer.

I got a solution for my own.

So, my requirement:

I have a custom pane, which contains a listbox, each item is a normal string. When I drag an item from the listbox into the document, at a specific location, I want to insert a merge field at that location. The name of the merge field is the text of the item.

It was simple at first, then I got a problem just like you describe in your question.

About the code

So, there is a listbox, you need to handle mouseDown and mouseMove, don't worry about mouseUp.

In mouseDown handler, I record the boundary, if the mouse moves out of that boundary, the drag will start.

Then, in listBox_MouseMoveHandler, I check position of the mouse to start the dragdrop. And I have to use DragDropEffects.Copy for the DoDragDrop method.

DoDragDrop((sender as ListControl).SelectedValue, DragDropEffects.Copy);

With that option, SelectedValue will be inserted at the drop position, and after it is inserted, it will also be selected.

Then, I just check if selection is not empty, and replace the selected text with the merge field. Of course, I collapsed the selection before DoDragDrop. And that is the whole trick.

    private int _selectedItemIndex;

    private Rectangle dragBoxFromMouseDown;

    private void CustomizationForListBox(ListBox listBox)
    {
        listBox.ItemHeight = 25;
        listBox.DrawMode = DrawMode.OwnerDrawFixed;
        listBox.DrawItem += ListBox_DrawItem;
        listBox.MouseDoubleClick += listBox_MouseDoubleClick;
        listBox.MouseMove += listBox_MouseMoveHandler;
        listBox.MouseUp += listBox_MouseUp;

        listBox.MouseDown += (sender, e) =>
        {
            // Handle drag/drop
            if (e.Button == MouseButtons.Left)
            {
                _selectedItemIndex = listBox.IndexFromPoint(e.Location);

                // Remember the point where the mouse down occurred. The DragSize indicates
                // the size that the mouse can move before a drag event should be started.                
                Size dragSize = SystemInformation.DragSize;

                // Create a rectangle using the DragSize, with the mouse position being
                // at the center of the rectangle.
                dragBoxFromMouseDown = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                                                               e.Y - (dragSize.Height / 2)), dragSize);
            }
        };

    }

    private void listBox_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            // Reset the drag rectangle when the mouse button is raised.
            dragBoxFromMouseDown = Rectangle.Empty;
        }

    }

    private void listBox_MouseMoveHandler(object sender, MouseEventArgs e)
    {
        // Handle drag and drop
        // To check if the Mouse left button is clicked
        if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
        {
            // If the mouse moves outside the rectangle, start the drag.
            if (dragBoxFromMouseDown != Rectangle.Empty &&
                !dragBoxFromMouseDown.Contains(e.X, e.Y))
            {
                // Collapse current selection, now we know nothing is selected
                Globals.ThisAddIn.Application.Selection.Collapse(WdCollapseDirection.wdCollapseEnd);

                //Start Drag Drop
                DoDragDrop((sender as ListControl).SelectedValue, DragDropEffects.Copy);
                if (_selectedItemIndex != -1)
                {
                    // If the drag/drop was successful, there dropped text must be selected
                    if (!String.IsNullOrWhiteSpace(Globals.ThisAddIn.Application.Selection.Text))
                    {

// Replace the selected text with a merge field MergeFieldHelper.InsertSingleMergeField(mergeFieldInfos[_selectedItemIndex].Name); } } } } }

vothaison
  • 1,646
  • 15
  • 15