Skip to content

NShape 2.3.0

Choose a tag to compare
@kholzinger kholzinger released this 24 Jun 11:56
· 7 commits to master since this release

NShape is now based on Framework 4.0 instead of Framework 2.0.
NuGet packages are now available for NShape.

Changes in 2.3.0:

Breaking Changes:

  • NShape is now based on Framework 4.0 instead of Framework 2.0.
  • The default shape base class ShapeBase now seals inherited methods like MoveBy, MovePointBy, Rotate, etc but introduces methods like MoveByCore, MovePointByCore, RotateCore, etc. that can be overridden in order to change the default behavior without having to reimplement code of the base class.
  • In order to achieve CLS compliancy and fulfill code guidelines, several protected fields were replaced with properties and therefore the casing changed:
    class ShapeBase:
    protected List<ShapeConnectionInfo> connectionInfos;
    protected bool drawCacheIsInvalid = true;
    protected bool isGluePointFollowingConnectionPoint = false;
    For all of these, a property with upper case first letter exists:
    protected List<ShapeConnectionInfo> ConnectionInfos { get; set; }
    protected bool DrawCacheIsInvalid { get; set; }
    protected bool IsGluePointFollowingConnectionPoint { get; set; }

New Features:

  • Move the visible area of a diagram by dragging the diagram with the mouse.
    The mouse button that triggers the drag action is adjustable with the PanMouseButton property of the display.
    Middle mouse button is the default.
    All demo programs support panning with middle and right mouse button.
  • Adjustable margin around the diagram sheet: Display.DiagramMargin
  • Localization support: All user relevant texts are defined as resource strings now, so you can create translated sattelite assemblies now.
  • Extended the number of supported layers.
    Each shape now has a HomeLayer property which is a single layer id. combination of layer ids.
    Additionally, the SupplementalLayers (former Layers) are available, which is a combination of LayerIds enums.
    For more details, see documentation (Concepts > Layers) for an explanaition of the new concept.
  • XmlStore now supports partial loading for improved performance.
    Partial loading is disabled by default (for backwards compatibility) and can be enabled using the XmlStore.LazyLoading property:
    When loading diagrams, the diagram instance is loaded without contents. The diagram contents have to be loaded explicitly by calling the IRepository.GetDiagramShapes method.
    Make sure that all GetDiagramShapes was called for all diagrams before saving.
  • XmlStore provides a new property ImageLocation which specifies whether images are stored in a seperate directory (as it was until now) or whether images are embedded into the XML file as base64 encoded string.
    When loading an existing XML file, the ImageLocation setting of the file will be determined and used until it the XmlStore is closed or the ImageLocation is overridden by setting the ImageLocation property while the XmlStore is open.
  • NShapeDesigner implements the new features:
    • "Upgrade Version" located in the "File" menu.
    • "Use Embedded Images" located in the "File" menu.
    • "Export Repository to Clipboard (XML)" located in the 'File' menu uses Project.GetXml.
    • "Import Repository from Clipboard (XML)" located in the "File" menu uses Project.OpenXml.

Interface Changes:

  • New PropertyController events:
    public event EventHandler<PropertyControllerEventArgs> SelectedObjectsChanging;
    public event EventHandler<PropertyControllerEventArgs> SelectedObjectsChanged;
    SelectedObjectsChanged replaces the ObjectsSet event, which is obsolete now.

  • New model object type for diagram model objects IDiagramModelObject : IEntity, ISecurityDomainObject

  • Added property ModelObject of type IDiagramModelObject to the Diagram class.

  • Added public Methods to WinFormsUi.ToolSetPresenter:
    ListViewItem CreateListViewItem(Tool tool)
    public ListViewItem FindItem(Tool tool)

  • Added method IDiagramPresenter.GetVisibleLayers()

  • Added static method Diagram.IsShapeVisible

  • Added overloaded versions of Diagram.CreateImage that accept the visible layers.

  • Not all menu items had names, but they should, so all MenuItemDef constructors now take a name as first parameter. As a consequence, all other constructors of MenuItemDef and derived classes are now deprecated. There are constants for the MenuItemNames.

  • As CommandMenuItems without a command make no sense, we changed the following:

    • All constructor overloads of the CommandMenuItemDef class are deprecated now.
    • The 'command' parameter of the CommandMenuItemDef constructors may no longer be null.
  • CaptionedShapeBase.CharacterStyle property is now virtual.

  • CaptionedShapeBase.ParagraphStyle property is now virtual.

  • TextBase's former private method FitShapeToText is now protected virtual.
    This method sets Width and Height to the Text's size and will be called in AutoSize mode when

    • the shape's Text property changes.
    • the shape's CharacterStyle changes.
    • the shape's ParagraphStyle changes.
      When overriding this method, make sure not to use anything from the draw cache as this method will be called in RecalcDrawCache before base.RecalcDrawCache() is called!
  • Replaced protected fields of class TextBase

  • Renamed TextBase's protected class GluePointCalcInfo to LabelPositionInfo.

  • Definition of the abstract StyleCollection base class changed from
    public abstract class StyleCollection<TStyle> where TStyle : class, IStyle
    public abstract class StyleCollection<TStyle, TStyleInterface> : IEnumerable<TStyleInterface>
    where TStyle : class, TStyleInterface
    where TStyleInterface : class, IStyle
    due to the fact that the implementation of the enumerator moved from the specific style collections to the base class which in turn wraps the enumerator of the internal list (see below).

  • IDisplayService.NotifyBoundsChanged is obsolete now. Use the Resized event of the diagram instead (see below).

  • Changed several event args classes:

    • EventArgs class ShapeMouseEventArgs (unused) was deleted.
    • EventArgs class ShapeEventArgs (unused) was renamed to ShapesEventArgs.
    • EventArgs class DiagramShapeEventArgs (unused) was renamed to DiagramShapesEventArgs.
    • EventArgs class ShapeEventArgs was added.
    • EventArgs class DiagramPresenterShapeEventArgs was added.
  • Data type of Geometry.Signum changed from int to sbyte.

  • Moved the following (never implemented) methods from class CachedRepository to class Project and implemented them:
    string GetXml()
    void WriteXml(Stream stream)
    void OpenXml(Stream stream)

  • IDiagramPresenter interface is now derived from ISynchronizeInvoke in order to enable thread synchronized timer events (when using System.Timers.Timer's property SynchronizingObject).

  • Added IDisplayPresenter.CloseCaptionEditor(bool applyChanges).

  • Added three events to IDisplayPresenter:
    event EventHandler<DiagramPresenterShapeEventArgs> ShapeMoved
    event EventHandler<DiagramPresenterShapeEventArgs> ShapeResized
    event EventHandler<DiagramPresenterShapeEventArgs> ShapeRotated

  • Added boolean property CanModifyVersion to the IRepository interface which specifies whether the current repository implementation supports upgrading the load/save version of the repository.

  • Added Method UpgradeVersion to the IRepository interface which will upgrade the load/save version of a repository (or throw an exception if upgrading is not supported).

  • Added boolean property CanModifyVersion to the Store base class.
    The shipped XmlStore will support upgrading load/save version whereas the shipped AdoNetStore will not.

  • Added the following members to the XmlStore class (see new features for details):
    bool LazyLoading { get; set; }
    ImageFileLocation ImageLocation { get; set; }

  • Added four events to the Diagram class:
    event EventHandler<ShapeEventArgs> ShapeMoved
    event EventHandler<ShapeEventArgs> ShapeResized
    event EventHandler<ShapeEventArgs> ShapeRotated
    event EventHandler Resized

  • Base class "Shape" was extended by the following protected members in order to enable custom collection implementations for the Shape.Children collection.
    protected ShapeAggregation ChildrenCollection { get; }
    Provides access to the collection that stores and manages the shape's child shapes. The collection is null by default and will be created when needed and deleted when not needed any more.
    protected virtual ShapeAggregation CreateChildrenCollection(int capacity)
    Creates an instance of the children collection with the given capacity. Override this method if a custom implementation of the children collection is needed.

  • Added two methods to the ICaptionedShape interface:
    bool GetCaptionIsVisible(int index)
    void SetCaptionIsVisible(int index, bool isVisible)

  • For implementing the new methods above, the Caption class got a new property
    bool IsVisible { get; set; }

  • Base class Tool has now a property DoubleClickTime that takes the interval (in ms) used for interpreting two subsequent clicks as double click.

  • Added three protected virtual methods to ReposioryWriter base class:

  • Added constructor overloads to the DelegateMenuItemDef class.

  • Added/Deprecated the following members because of the layer concept changes:

    Interface IDiagramPresenter
    Deprecated Members:
    LayerIds ActiveLayers { get; }
    LayerIds HiddenLayers { get; }
    Added Members:
    ICollection<int> ActiveLayerIds { get; }
    ICollection<int> HiddenLayerIds { get; }
    LayerIds GetVisibleLayerIds();
    void SetLayerActive(int layerId, bool active);
    void SetLayerActive(IEnumerable<int> layerIds, bool active);
    void SetLayerActive(IEnumerable<Layer> layers, bool active);
    void SetLayerVisibility(int layerId, bool visible);
    void SetLayerVisibility(IEnumerable<int> layerIds, bool visible);
    void SetLayerVisibility(IEnumerable<Layer> layers, bool visible);

    Interface ILayerCollection
    Added Members:
    int GetNextAvailableLayerId();

    Class Diagram
    Deprecated Members:
    public void AddShapeToLayers(Shape shape, LayerIds layers)
    public void AddShapesToLayers(IEnumerable<Shape> shapes, LayerIds layerIds)
    public void RemoveShapeFromLayers(Shape shape, LayerIds layers)
    public void RemoveShapesFromLayers(IEnumerable<Shape> shapes, LayerIds layers)
    Added Members:
    public static bool IsShapeVisible(Shape shape, LayerIds visibleLayers, ICollection<int> visibleHomeLayers)
    public void AddShapeToLayers(Shape shape, int homeLayer)
    public void AddShapeToLayers(Shape shape, IEnumerable<int> layerIds)
    public void AddShapeToLayers(Shape shape, int homeLayer, LayerIds supplementalLayers)
    public void AddShapesToLayers(IEnumerable<Shape> shapes, int homeLayer, LayerIds supplementalLayers)
    public void RemoveShapeFromLayers(Shape shape)
    public void RemoveShapeFromLayers(Shape shape, int homeLayer)
    public void RemoveShapeFromLayers(Shape shape, int homeLayer, LayerIds layers)
    public void RemoveShapesFromLayers(IEnumerable<Shape> shapes, int homeLayer)
    public void RemoveShapesFromLayers(IEnumerable<Shape> shapes, int homeLayer, LayerIds supplementalLayers)
    public Image CreateImage(ImageFileFormat imageFormat, IEnumerable<Shape> shapes, IEnumerable<int> visibleLayerIds, int margin, bool withBackground, Color backgroundColor, int dpi)

    Class DiagramSetController
    Deprecated Members:
    public void InsertShape(Diagram diagram, Shape shape, LayerIds activeLayers, bool withModelObjects)
    Added members:
    public void InsertShapes(Diagram diagram, IEnumerable<Shape> shapes, IEnumerable<int> activeLayerIds, bool withModelObjects)

    Class Layer
    Added Members:
    public const int NoLayerId = 0
    public static LayerIds ConvertToLayerIds(int layerNo)
    public static LayerIds ConvertToLayerIds(IEnumerable<int> layerNos)
    public static LayerIds ConvertToLayerIds(IEnumerable<Layer> layers)
    public static int ConvertToLayerId(LayerIds layerId)
    public static bool IsCombinable(int layerNo)

    Class NamedImage
    Added Member:
    string ImageHash { get; }

Changed Behavior:

  • The constructors of NamedImage no longer clone the given image in order to avoid unnecessary image copying.
    So if you create a NamedImage e.g. from embedded resources, you have to clone these resources new instead of passing them to the constructor directly.
  • The CachedRepository now allows the assignment of a store while repository is open in case that no store exists yet.
  • Display.ScrollWithMouseWheel is enabled by default now.
  • Display.UseUniversalScroll is disabled by default now.
  • Reverse scaling of line cap shapes is now done in the ToolCache.
    The cap's vertexes are scaled down when calculating them so the automatic upscaling of GDI+ scales them the desired size.
    Therefore, the cap's graphics paths no longer need to be scaled when drawing them.
  • When loading an existing repository in NShapeDesigner, it will no longer automatically create a diagram if the repository has no diagram.
    Newly created repositories are not affected.
  • Display.CopyImageToClipboard function did not execute the same code as the appropriate display context menu item.
    Now it does: Image will be copied with background if no shapes were selected and without background if shapes were selected.
  • Permissions for 'Aggregate Shapes' and 'Disaggregate Shapes' commands changed from 'Present' to 'Layout'.
  • NShapeDesigner no longer asks for a file name when creating a new XML project.
    Instead, no store is created in this case in the first place. It will be created when saving the project for the first time.
  • Holding down the control key while moving a shape means now 'Toggle snapping to grid' instead of 'Do not snap to grid'.
  • When clicking on overlapping shapes (with OverlappingShapesAction != None), the selection of the next/topmost shape will be deferred until the double click detection time elapses.
  • Tools never received MouseUp events with clicks > 1 because WinForms controls reset the click count before raising the MouseUp event of the double click's second click.
    In Addition to that, multi-clicks are now supported (tripple-click, quadruple-click, etc) as the click count will not be reset after a double click (as WinForms controls do).


  • The context menu of the display did not show if the display had no ActiveTool.
    Now, it shows even if the display has no ActiveTool and displays only the context menu entries from the display in this case.
  • Hiding a display's scrollbars does no longer prevent scrolling the display.
  • ModelObjectBase.DetachShape() no longer throws exceptions if the given shape is not attached to the model object.
  • KeyNotFoundException when saving XML repository with embedded images.
  • Solved several NullReferenceExceptions when Display's ActiveTool is null.
  • The CachedRepository now disposes its cached resources correctly.
  • XmlStore's buffers for diagrams to load and embedded images are now reset correctly when closing the store.
  • Some ICommand implementations used Int32 instead of ControlPointId as data type for control point ids.
  • A bug in CaptionedShapeBase.CopyFrom has been fixed: The ParagraphStyle was not copied.
  • When a shape was connected to a connection point at the end of a line and the line was rotated around this point, the connected shape's FollowConnectionPointWithGluePoint method was not called.
  • PolylineBase did not respect the MaxVertexCount of the line in DrawThumbnail().
  • Renamed the RegularPolygonBase's EntityField from "Diameter" to "Radius" because it stores the radius, not the diameter.
  • When rotating an unconnected label, the label's pin glyph was drawn incorrectly.
  • Geometry.CalcBoundingRectangle(IEnumerable<PointF> points, out Rectangle rect, bool floor) did not calculate a correct bounding rectangle when all points had the same X coordinate.
  • Geometry.CalcNormalVectorOfLine() no longer changes the normal vector's direction depending on the line's slope.
  • When using XmlStore and embedded images, saving project, creating a picture shape and saving again no longer crashes.
  • Changing the StyleCollection iterator's implementation (see above) fixes a bug where you can change the collection's key while iterating through the collection.
    Doing so will now raise an InvalidOperationException.
  • EmbeddedImageWriter now calls all IEntity.SaveFields and IEntity.SaveInnerObjects methods with the library's version instead of the base repository version.
  • Moving shapes with arrow keys will no longer focus the scroll bars (which will break scrolling and zooming behavior).
  • The display component no longer runs into an exception when pressing F2 while an ICaptionedShape without captions is selected.
  • Selecting shapes inside a group (or double clicking overlapping shapes) does no longer cause the Display.ShapesSelected event to be fired multiple times when OverlappingShapesAction is set to OverlappingShapesAction.Cycle.
  • RegularPolygone now draws itself in the correct size after loading from repository
  • Fixed a NullReferenceException when dragging a group of shapes loaded from XML repository
  • Saving picture shapes with to XML store with with ImageLocation == Embedded on caused a NullReferenceException.
  • Image directory was not deleted when deleting an XML repository (ImageLocation == Directory).
  • Fixed a backwards compatibility issue in XML store:
    Files created with NShape versions <= 1.0.3 could not be read with NShape versions >= 1.0.4.
  • Clicking the save button in NShapeDesigner while editing the caption of a shape will no longer cause an exception.
  • NShape components will now remove all registered event handlers propertly.
  • Undoing "ungroup" on a rotated group now reverts the rotation of the group members correctly
  • When creating linear shapes, the connection points near the mouse cursor are now drawn.
  • Constructor AggregatedCommand(IRepository repository, IEnumerable commands) no longer raises a NullRegerenceException.
  • XmlRepositoryReader.ReadDate() did not advance the underlying XmlReader to the next attribute.
  • XmlStore backwards compatibility issues fixed:
    NShape 1.0.0 to NShape 1.0.3 "Repository Version 2" stored templates including their title.
    NShape 1.0.4 to NShape 2.1.1 neither store nor read the template's title for version 2 repositories, thus breaking compatibility with old repository files.
    As NShape 1.0.4 also introduced the "Repository Version 3" storage format (default for new projects), we repaired the compatibility issue so you can now open "Version 2" repositories created with NShape 1.0.0 to 1.0.3 but not "Version 2" repositories created with NShape 1.0.4 to NShape 2.1.1.
    If you need to open old version 2 files, please insert an attribute "title" between the "name" and the "description" attribute of all template tags:
    <template id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name="xxxxxxxx" description="">
    <template id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" name="xxxxxxxx" title="" description="">
  • The project component no longer accepts version 1 as minimum repository version. Version 2 is the correct minimum load/save version as NShape 1.0.0 was released creating version 2 repositories.
  • XmlStore did never call SaveInnerObjects method of model objects.
  • Added a workaround for an issue that causes an OutOfMemoryException in the underlying GDI+ Flat API functions when trying to draw lines with intersecting line caps.


  • Improved drawing performance of the diagram sheet's line grid noticeably.
  • The Text and CaptionStyle properties of shapes implementing ICaptionedShape now use the Interface methods for modifing the shape's text and caption style properties instead of the interface methods using the properties.
  • LinearShapeCreationTools now handle MouseDown and MouseUp events instead of only handling the MouseClick event.
    The shapes will be created when releasing the mouse button.
  • Added generic versions of Template.CreateShape() for more convenient shape creation.
  • Renamed all fields so they do no longer collide with property names in case insensitive .NET languages such as VB.NET.
  • Support for large diagram background images by drawing a lower resolution version while editing.
  • The NShapeSecurityException constructor accepting a command only will now build better error messages.
  • Improved RoleBasedSecurityManager's performance.
  • The "ExportDiagramDialog" also has a new check box "Export only shapes of visible layers"
  • NShapeSecurityExceptions will be catched by the NShapeDesigner's ThreadException handler.
    A normal error message box will be shown instead of the "Do you want to terminate the application?" message box.
  • The SelectionTool's context menu item "Select > Shape of Type" now uses the selected shapes (if there are any).
  • Improved IDisposable implementation of shapes.
  • In .NET 4.x, the implementation of Clipboard.SetData() has changed:
    The clipboard will always be emptied when calling the function. In order to be able to copy both, an EMF and a Bitmap image to the clipboard, there are 2 new methods:
    Display.CopyImagesToClipboard(bool clearClipboard)
    Display.CopyImagesToClipboard(IEnumerable<int> visibleLayers, bool clearClipboard)
  • XmlStore's embedded images that are used many times are now saved only once.
  • StyleCollections will now handle renaming styles and maintain their name based indexer automatically in this case.
  • When selecting a shape and dragging it away within the double click detection time will now be handled as expected.
  • XmlStore has an additional constructor that takes a stream instead of a directory and a file extension.
    If the XmlStore was constructed using this constructor, the stream will be used for loading/saving for the lifetime of the XmlStore.
  • Inserting diagrams with duplicate names in the repository will now raise an exception.
  • You can now select "None" as color for line caps. In this case, the line cap will be filled with the color of the line.
  • Updated all demo projects to version 7 (using embedded images).
  • Updated documentation to reflect all interface changes of the last few versions and added several yet undocumentated classes.