GoDigram for .NET Framework and .NET Core
Northwoods.Go Namespace / GoDocument Class
Members Example
In This Topic
    GoDocument Class
    In This Topic
    This class represents a model for a GoView, holding GoObjects to be displayed, organized into GoLayers.

    To show something in a GoView, you will need to construct and initialize a GoObject (typically a class inheriting from GoNode or GoLink or GoLabeledLink), and then add it to the view's GoView.Document, which will be an instance of GoDocument.

    Please note that a GoDocument does not require the existence of any GoViews. A document may have zero, one, or many views displaying it simultaneously. A document and all of its GoObjects must not have any references to any GoView or to any other Controls.

    All documents and all of their objects must be serializable. Please read more about this topic in the User Guide. To help debug serialization issues, call the TestSerialization method.

    GoDocument implements IGoCollection, so you can call methods such as Add, Remove, Contains, Clear, and CopyArray, use properties such as Count, and enumerate both forwards and Backwards.

    A GoDocument organizes all of the GoObjects that it contains into GoLayers. The layers are held in the Layers collection. Initially a document will only have one layer, the DefaultLayer. If you want to keep nodes in one layer and links in a different layer, it is conventional to put the nodes in the DefaultLayer and the link in the LinksLayer. You will need to create a new layer and assign it to that property. If you want have all links appear behind all nodes, you can do:

    doc.LinksLayer = doc.Layers.CreateNewLayerBefore(doc.Layers.Default)

    Since the layers are painted in the order in which they appear in the Layers collection, the above code will ensure that all links are painted before any nodes or other objects that are in the DefaultLayer.

    The GoObject.Bounds of each object are in document coordinates. This means that the coordinates are single precision floating point values; the position is a PointF, the size is a SizeF, and the bounds is a RectangleF. Each GoView can look at some or all of the GoObjects in a rectangular area determined by the view. The size of the view, the view's GoView.DocPosition, and the view's GoView.DocScale all together form the view's GoView.DocExtent. If a GoObject's GoObject.Bounds is outside of a view's GoView.DocExtent, it won't be seen in that view.

    Independent of any view, a GoDocument has a Size and a TopLeft position. Together they form the document's Bounds. Normally the document's bounds is large enough to include the bounds of all of its objects. As objects are added or moved or resized, UpdateDocumentBounds extends the TopLeft position and the Size if needed. (However, if FixedSize is true, UpdateDocumentBounds does nothing.) The document's bounds affect whether or not a particular view's scroll bars are needed and how far a user might be able to scroll. But note that each view has additional properties for governing scrolling extents.

    The document's bounds do not automatically shrink as objects are removed or are moved away from the edges of the bounds. To iterate over all of the objects and compute the actual area that they currently occupy, call ComputeBounds. You can also call the static method ComputeBounds(IGoCollection,GoView) to determine the extent of any collection of objects. That method takes an optional GoView argument to allow consideration of how much area each object actually takes when painted or printed in that view, since for each object the result of GoObject.ExpandPaintBounds may be larger than then the object's GoObject.Bounds.

    There are a number of different possibilities for finding an object in a document: by location, by name, or by identifier.

    To find the front-most object at a given point, call the PickObject method. If you might want to find all of the objects at a particular point, including those hidden behind/underneath, call the PickObjects method. If you want to find all of the objects that are either completely or partially surrounded by a rectangular area, call PickObjectsInRectangle.

    To find a node by name, call one of the FindNode methods. FindNode actually will find any IGoLabeledPart, not just nodes. IGoLabeledPart.Text is the property that provides the text string.

    To find a node or port or link by integer identifier, you'll first need to set MaintainsPartID to true. Then you'll be able to call FindPart to find any IGoIdentifiablePart within the document, at any level of nesting. IGoIdentifiablePart.PartID is the property that provides the integer identifier.

    There are many properties that control whether a user can perform certain operations. These properties (and corresponding predicates) are defined by the interface IGoLayerAbilities. Those include: select, move, copy, resize, reshape, delete, insert, link, and edit. Setting one of these Allow... properties will affect all GoViews displaying this document. (Setting the same properties on a view will only affect that view; setting the same properties on a layer will only affect all objects in that layer.) Call the SetModifiable method for a convenient way to set all of the properties that allow modification of the document.

    The IsModified property indicates whether the document has been modified. Read its documentation to learn more about how the GoUndoManager affects its state, for both getting and setting.

    Whenever a change to the document occurs, the Changed event is raised. Each time one sets a property or adds or removes an object, RaiseChanged is called, which in turn calls OnChanged to call all registered event handlers. OnChanged is also responsible for maintaining the IsModified state, for calling UpdateDocumentBounds, and for maintaining IGoIdentifiablePart.PartIDs.

    If you add a property in a class inheriting from GoDocument, be sure to call RaiseChanged if and only if the value has changed. You will also need to override ChangeValue to perform the recorded change for that particular property. Similarly, if you add a property to a class inheriting from GoObject, be sure to call GoObject.Changed if and only if the value has changed. You will also need to override GoObject.ChangeValue in that class to perform the recorded change for that particular property.

    To record undo/redo information, assign the UndoManager property. This will automatically enable undo/redo functionality in all views displaying this document. If you want to make some transient changes to objects and do not want those changes to be recorded in the GoUndoManager, temporarily set SkipsUndoManager to true.

    Any code that makes changes to a document or to a document object should be preceded with a call to StartTransaction and followed by a call to FinishTransaction or AbortTransaction. This groups together all of the changes so that an undo or a redo will perform them all at once. Transactions can be nested.

    When you want to (programmatically) make copies of objects and add them to a document, call AddCopy for a single object or call CopyFromCollection(IGoCollection) for multiple objects. Calling the latter method (or its overloaded variant, for more options) is needed if you want to maintain relationships between the objects being copied, for example, the links between nodes.

    GoDocument also provides some options for controlling the kinds of links that users may draw: the ValidCycle property.

    For document persistence, you will need to implement code to read/write to your desired medium. If you are reading/writing XML, you may find GoXML useful. In particular, GoXmlBindingTransformer may be very convenient to use. We also offer a sample, DataSetDemo, demonstrating persistence to and from a DataSet.

    Read the User Guide and FAQ for more details.

    Typical programmatic usage might be something like:
    GoBasicNode node1 = new GoBasicNode();
    node1.LabelSpot = GoObject.Middle;
    node1.Text = "basic node 1";
    node1.Shape.BrushColor = Color.LightGreen;
    node1.Location = new PointF(75, 50);
    GoBasicNode node2 = new GoBasicNode();
    node2.LabelSpot = GoObject.Middle;
    node2.Text = "basic node 2";
    node2.Shape.BrushColor = Color.LightYellow;
    node2.Location = new PointF(200, 50);
    GoLink link = new GoLink();
    link.ToArrow = true;
    link.FromPort = node1.Port;
    link.ToPort = node2.Port;
    See Also