Aracılığıyla paylaş


Orphan Shape in the Class Designer

One of the biggest value propositions of the Class Designer is to keep class diagrams always in-sync with code – in fact it is supposed to be another view of your code. Code is the ‘model’ behind class diagrams. If you open a class diagram file in an xml editor you will find that all it contains is the visual information – placement of the shapes, hidden members if any, association lines if any, etc. The thing that associates a shape to code is the fully qualified name of the type it is representing and the source artifact that type is defined. You can find more information on the file format of class diagrams in an upcoming blog post.

When you open a class diagram, Class Designer will look for the type associated with each shape by its fully qualified name and associate it with the shape. The members of the type are dynamically populated by parsing the source files or retrieving it from the assembly (as the case may be). If the class diagram is open, the class designer will listen to change events to update the diagram to reflect the changes made to the code. When you save the diagram, the fully qualified name of the type and the artifact it came from (source file/assembly) will be persisted in the diagram file.

However, what happens if you rename a class (or its namespace) with the class diagram closed? Or what if, in a team scenario, somebody just checks out source code, makes the changes and checks it back in, without updating the diagram? When the diagram is opened, since Class Designer will try to associate the shape with the fully qualified name of the type, it won’t be able to find the shape’s type and load the member information. If it is unable to find a shape’s type Class Designer will remove the shape from the diagram. But you might have spent considerable effort customizing your shape – for example, grouped them by access, hidden some of the members, shown some of the members as association lines, manually placed line ends etc. If the class designer removed the shape you’d have to redo the whole thing again (of course if you had the diagram opened while you refactored your code, Class Designer will be able to listen to the change events and update the diagram).

Here are a couple of shapes before customization.

Here are the shapes after the following customizations:

  • XmlNode
    • Methods compartment is collapsed to hide all methods.
    • The Attributes property is shown as a line pointing to XmlAttributeCollection class, rather than just a regular member inside the shape.
    • The following properties are hidden on the diagram: BaseURI, InnerXml, IsReadOnly, LocalName, NamespaceURI, NextSibling, OuterXml, OwnerDocument, Prefix, PreviousSibling, SchemaInfo.
    • “Lollipop” is collapsed – the diagram now communicates that the class implements one or more interfaces, but it isn’t important to show in this diagram precisely which interfaces are implemented.
  • XmlAttributeCollection
    • Shape is collapsed to hide all its members.
    • Width is increased so that entire name is readable.

Class Designer has a couple of cool features that helps you preserve your shape customizations in scenarios described earlier (refactoring your code with the class diagrams closed). I mentioned earlier the thing that associates a shape to code is the fully qualified type name and the source artifact name. Well, there is one additional piece of information that is also stored for a shape – a hash code value. This value is computed from the member signatures (other than constructor/destructor) of the various members in the class. When the class diagram is opened, if the class designer cannot find the type in the source file, it will look for other classes defined in the same file and compute the hash value for those classes. If it finds one that falls within a certain pre-determined threshold percentage, then class designer will assume that type to be the one representing the shape and associate it with that shape. Obviously, this heuristic will work better if the class has more members. The reason we don’t require an exact match of the hash value is because it is likely that along with the rename, you might have added or changed a few members. But it may be the case that you also changed the file name along with the class name. If this is so, the class designer will go through all the files in your project and try to find a class that is the best match. Note if your project contains a lot of files this will result in a delay in opening the diagram. If your project contains more than 50 files, Class Designer will give you an option of doing this search or not.

Under what circumstances will I see orphan shapes in my diagram?

The class designer makes a reasonable effort to keep your diagram intact by using this heuristic. However, as any solution based on heuristics, it is likely that there are situations where Class Designer cannot make an association between a shape and the type it represents. Or you may have a large project and choose to not wait for Class Designer to search through all the files to look for a match. In such situations, when you open a diagram, you will get what we call an “Orphan” shape on the diagram for any shapes that cannot be associated with its type. Here is an example:

The following table lists the possible causes for an orphaned shape in your diagram.

If user does the following

while diagram is closed

Class Designer will react as follows

at diagram load time

Class code is significantly changed such that CD can no longer associate the shape with its code.

Shape is displayed as orphaned. The user can delete the shape or associate it with existing code.

Deletes class

Shape is displayed as orphaned.

Removes reference to assembly or project

Shape is displayed as orphaned.

Unload referenced project (class resides in the referenced project)

Shape is displayed as orphaned.

Delete or remove class’ source code file from project

Shape is displayed as orphaned.

Moves class to another file

Class Designer should be able to associate the shape and its code, as long as the code has not significantly changed.

If you hover over the shape you will get tooltip text that says code is missing for the shape and how you can associate the shape back to the type.

As the tooltip text suggests, you can either type in the new fully qualified name for the shape (either in-place on the shape or in the property browser) or drag and drop the renamed type from Class View. Once this association is made, the Class Designer will restore the shape with all the customizations that still apply including lines coming to and going from the shape!

A simple walkthrough:

The following section provides a simple walk through that lets you experiment with this feature:

1. Create a new C# class library. In the auto-generated class Class1, add a new method foo which looks like this:

                      public void foo(int i)

                      {

                      }

2. Create a new class diagram which looks like

3. Save and close the diagram.

4. In source code, rename class Class1 to MyClass

5. Re-open the diagram and you will see that the diagram now shows class MyClass

In this example, Class Designer’s heuristics determined that there is a high probability that the shape that used to be associated with Class1 ought to be associated with MyClass. In most cases, the heuristic can reconcile differences well enough to re-associate shapes to types. In the event it cannot, please read on…

You can re-associate an orphaned shape to a type using one of the following methods:

1. Drag/drop a type node from Class View onto the orphaned shape. The orphaned shape will display appropriate drop target feedback when a Class View type is dragged onto it for re-association.

           Here are a couple of things to keep in mind:

a. You cannot drop a selection containing multiple types from the Class View onto an orphaned shape. If you try to do so, a no-smoking icon will appear to indicate that the shape is rejecting the types.

b. You cannot drop a type from Class View onto an orphaned shape if the type is already represented by another shape on the diagram. A no-smoking icon will appear to indicate that that type cannot be dropped on the shape.

2. Rename the shape to match the name of the type that you want it to be associated with. You can rename a shape by single-clicking on its name; this will put you in edit mode. Alternatively, you can right-click on the orphan shape and choose “Relink Shape with Code” and then enter the name of the type that you want the shape to be associated with. When you’re done, press ENTER to commit the change.

3. Another alternative is simply to rename the class in the code file to match the name of the orphaned shape. Class Designer automatically will recognize the match and associated the type with the shape.

4. Or, if you don’t want the orphaned shape anymore, you can simply delete it.

Ramesh Rajagopal and Patrick Tseng

Microsoft Visual Studio Class Designer Team

Comments