How do I remove a Shape from an axDrawingControl?

Started by eggmatters, February 02, 2011, 09:15:29 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

eggmatters

It may sound simple, but I'm having difficulties trying to do just that. What I'm doing is going through an existing Visio (2003) and copying each shape I need to an arraylist of Visio.Shapes. I then want to display each shape in a different form containing an axDrawingControl. The user clicks a button which displays a shape in the list. Each click displays the next shape. This works fine except that it just displays the newer shape on top of the old one. It is worthwhile to note that in order to actually display the shape, I need to keep the original document open (I got an "access violation" exception if I closed the document and tried to preserve the shapes collection just in memory.) If I attempt to cut a shape or delete it, I get the same access violation. I don't want to alter the original document, I just want to display a shape and then hide it or remove it somehow when the click event occurs. Here is my code so far:


       private void showVisioShape_Click(object sender, EventArgs e)
       {
           try
           {
               //incrementer is the index of the current shape being shown in the collection
               if (incrementer > 0)
               {
                   //We should have a shape on the screen, let's remove it.
                   //getShape returns a Visio.Shape from the collection by index.
                   Visio.Shape oldShape = getShape((ReturnObj)myVisioShapes[incrementer - 1]);
                   //The following throws an exception "Inappropriate target object for this action.
                   axDrawingControl1.Window.Select(oldShape, 2);
                   //Commenting out the above, I can select the shape on the form (the drawing control) manually - actually, it appears selected by default. calling:
                  axDrawingControl1.Window.Selection.Delete();
                  //The above throws the access violation. The cut method does too. It's trying to cut a shape on the original document, which I don't want.
                }
           //getRetObj simply populates a storage class instance, myReturnObject, of which a member is a visio shape.
           if (getRetObj() < 0)
                   return;
               Visio.Shape myShape = getShape(myReturnObject);    
               //This bit works famously.            
               axDrawingControl1.Document.Pages[1].Drop(myShape, 2.50, 2.50);
           }
           catch (Exception ex)
           {
               MessageBox.Show(ex.Message + "\n" + ex.StackTrace);
           }

       }    


So that's it in a nutshell. Should I just create a dummy visio document which is a copy of the original? That seems rather kludgey but hey! It's COM!


eggmatters

One other note to mention. I'm getting the access violation exception due to the fact that The original shapes have layer protection turned on. Forgot about that.

eggmatters

Don't everybody jump on this at once. I think I have it solved. The original Visio had shape Protection locks on all of the shapes. in the code, when I get my shape, I have to remove that:

myShape.get_CellsSRC((short)Microsoft.Office.Interop.Visio.VisSectionIndices.visSectionObject,
                                                    (short)Microsoft.Office.Interop.Visio.VisRowIndices.visRowLock,
                                                    (short)Microsoft.Office.Interop.Visio.VisCellIndices.visLockDelete).FormulaU = "0";


eggmatters

What surprises me is that it seems like nobody has ever tried to open a Visio and port shapes to an Active X drawing control (Or at least delete them.) The SDK doesn't cover 'em at all. After getting these nagging "Requested operation is presently disabled" and not quite finding relevance to my my operation of simply deleting a shape, I fiddled, researched and finally came up with something that works:

//get a shape and drop it on your axDrawingControl: (The shapes have been loaded from a file)
//myReturnObject in part contains an aray of Visio.Shape(s) from said file.
Visio.Shape myShape = getShape(myReturnObject);
//unprotect the shape (IF you know that your shapes are not protected, no need to worry. But once again, the Row Column Cell structure of shape properties and elements if rather poorly documented.
unprotect(ref myShape); // See next code block for details:
//drop the shape:
axDrawingControl1.Document.Pages[1].Drop(myShape, 2.50, 2.50);


To unprotect various shape properties, you need to call Shape.get_CellsSRC(visSectionObject, visRowIndices.<flags - in this case visRowLock>, VisCellIndices.<flags - in this case visLock(whatever property to unlock>).FormulaU = "0";
Intellisense will do a good job of showing you the different enumerable properties, but there's no tooltip, MSDN, SDK reference documentation publicly available as to what they actually represent / do.


//Unprotect Shapes from deletion, selection and moving - right click a visio shape: select format->protection to see a list of protectable properties.
        private void unprotect(ref Visio.Shape thisShape)
        {
            String label;
            label = thisShape.get_CellsSRC((short)Microsoft.Office.Interop.Visio.VisSectionIndices.visSectionObject,
                                         (short)Microsoft.Office.Interop.Visio.VisRowIndices.visRowLock,
                                         (short)Microsoft.Office.Interop.Visio.VisCellIndices.visLockDelete).FormulaU = "0";

            label = thisShape.get_CellsSRC((short)Microsoft.Office.Interop.Visio.VisSectionIndices.visSectionObject,
                                         (short)Microsoft.Office.Interop.Visio.VisRowIndices.visRowLock,
                                         (short)Microsoft.Office.Interop.Visio.VisCellIndices.visLockSelect).FormulaU = "0";

            label = thisShape.get_CellsSRC((short)Microsoft.Office.Interop.Visio.VisSectionIndices.visSectionObject,
                                            (short)Microsoft.Office.Interop.Visio.VisRowIndices.visRowLock,
                                            (short)Microsoft.Office.Interop.Visio.VisCellIndices.visLockMoveX).FormulaU = "0";

            label = thisShape.get_CellsSRC((short)Microsoft.Office.Interop.Visio.VisSectionIndices.visSectionObject,
                                         (short)Microsoft.Office.Interop.Visio.VisRowIndices.visRowLock,
                                         (short)Microsoft.Office.Interop.Visio.VisCellIndices.visLockMoveY).FormulaU = "0";
        }


You can cut, move and delete the shape manually on the form (the axDrawingControl). To do this problematically, you can't apparently invoke the shape with something like:

//doesn't work:
Visio.Shape oldShape = (myShapetoDelete);
axDrawingControl1.Window.Select(oldShape, (short)Microsoft.Office.Interop.Visio.VisSelectArgs.visSelect);
axDrawingControl1.Window.Selection.Delete();
//Neither does this:
int myOldID = myShapetoDelete.ID;
axDrawingControl1.Document.Pages[1].Shapes.get_ItemFromID(myOldID).Delete();
// nor did any other permutations. The above two throw the "Requested operation is presently disabled" exception.


So what worked finally was this:

//set focus to the control. Known microsoft issue.
axDrawingControl1.Focus();
//Use the "DoCmd" operation isntead of what the seemingly straightforward option that didn't work above.
//What is "visCmdUFEditSelectAll" or the hundreds of other flags listed in the SDK reference? Beats me. No descriptions, how to use, when to use, what they do or anything.
axDrawingControl1.Window.Application.DoCmd((short)Visio.VisUICmds.visCmdUFEditSelectAll);
//This works now.
axDrawingControl1.Window.Selection.Delete();


So this begs a few questions:
1. DoCmd looks to integrate COM functinality with all of the specific application operations - seemingly. If so, why are there other ways to do some of these? Setting text collor, moving a shape etc?
2. What are the design considerations for this function? When do you use it? When do you not use it?