Class Part

GoDiagram®
v10.0.11
by Northwoods Software®

This is the base class for all user-manipulated top-level objects. Because it inherits from Panel, it is automatically a visual container of other GraphObjects. Because it thus also inherits from GraphObject, it also has properties such as ActualBounds, ContextMenu, and Visible.

Namespace: Northwoods.Go
Assembly: Northwoods.GoDiagram.Avalonia.dll
Syntax
public class Part : Panel, IHasContextMenu, IHasToolTip
Remarks

If you just want an object that users can select and manipulate, you can create an instance of this class.

If you want an object that also supports being connected by links to other objects, use the Node class, which inherits from Part. Create those connections by using instances of the Link class.

If you want a node that logically contains a subgraph of nodes and links, use the Group class, which inherits from Node.

If you want an object that decorates another Part, without having to modify that Part, use the Adornment class. Adornments do not support linking or grouping or being selected.

You can construct a Part, add GraphObjects to it programmatically, and then add the part to a diagram by calling Add(Part). However it is commonplace to add data to a model by setting its NodeDataSource or calling AddNodeData(TNodeData), or for Links, setting the LinkDataSource or calling AddLinkData(TLinkData). Such actions will cause a diagram that is displaying the model to copy a template, which is a Part that may have data Bindings, and add the new part to the diagram. The Data property will refer to that data object in the model.

Some examples of adding Parts to a Diagram:

// A simple Part template
myDiagram.NodeTemplate =
  new Part(PanelLayoutHorizontal.Instance)
    .Add(
      new Shape("Circle") { Width = 20, Height = 20 },
      new TextBlock("Hello World")
    );
// Node templates can be either Nodes, or simple Parts
// (But not Groups, Adornments, or Links)

// Adds copies of the NodeTemplate bound to the specified node data:
myDiagram.Model.NodeDataSource = new List<MyNodeData> {
  new MyNodeData { Key = "Alpha" },
  new MyNodeData { Key = "Beta" }
};

// Adds one copy of the NodeTemplate bound to the given node data:
myDiagram.Model.AddNodeData(new MyNodeData { Key = "Gamma" });

See the Introduction on using Models for examples and more information.

Layers and Z-ordering

Parts added to a Diagram exist in one of the Diagram's Layers. You can specify which layer the part should be in by setting LayerName. Parts cannot be nested in the visual tree -- they cannot be added to other Parts of Panels.

Parts can be individually z-ordered within a layer by setting ZOrder. Parts within the same layer that have a higher z-order number will be drawn above parts with a lower number.

Size and Position

The size and position of a part are given by its ActualBounds. The size is determined by the GraphObjects that are elements inside this part. You can change the position by setting Position or Location.

The "location" of a part is commonly the same as its "position". The "position" is always the point that is at the top-left corner of the area occupied by the part. But the "location" may be different from the "position" if you want to think of the part as being "at" a different spot in the part. For example, you might want the "location" to be at the center of a Picture that has a TextBlock title of arbitrary size. In this case you would set the LocationSpot to be Center and the LocationElementName to be the name of the Picture element in your Part.

A part may be selected or de-selected by setting its IsSelected property. This may also happen due to a call to Select(Part) or other operations that change the selection. The user may change this property as part of the operation of the ClickSelectingTool, due to the user's mouse click, if the part is Selectable.

Ability Properties (Permissions)

There are many properties named "...able", that control what operations the user may perform on this part. These properties correspond to the similarly named properties on Diagram and Layer that govern the behavior for all parts in all layers or for all parts in the given layer. For example, the Copyable property corresponds to the properties AllowCopy and AllowCopy.

For each of these "ability" properties there is a corresponding "Can..." predicate. For example, the CanCopy() predicate is false if any of the three previously named properties is false. Commands and tools will normally call these predicates rather than just looking at Part properties.

For more discussion about permissions, please read: Permissions.

As previously mentioned, each Diagram supports the notion of selected parts. One way of displaying that a part is selected is by modifying the part. You can set the SelectionChanged property to be a function that is called when the value of IsSelected has changed; it is passed the Part as the first argument. The function can modify the color of one or more GraphObjects in the visual tree of that Part. Or perhaps it could toggle the Visible property of an object that is normally hidden when the part is not selected.

The Part class also supports showing separate visual objects for a part when it gets selected. These visuals are typically used to show that the part is selected ("selection handles") or are used to allow the user to manipulate or modify the part with a tool ("tool handles"). These handles are instances of Adornments. The UpdateAdornments() method is responsible for showing or hiding adornments, normally depending on whether the part is selected.

When the SelectionAdorned property is true, a selected part automatically gets an Adornment created for it. By default the selection adornment is just a simple blue box around the Part, and a blue shape following the route of a selected Link. However you can set the SelectionAdornmentTemplate to an arbitrarily complex Adornment. This way it can show more information or buttons for executing various commands when the user selects a Part.

Tool handles are shown for those mode-less mouse-down tools that need it. The process of updating adornments for a part will call UpdateAdornments(Part) on each tool in MouseDownTools. Most tools might not need special tool handles. But, for example, ResizingTool naturally will want to create an adornment with eight resize handles positioned at the corners and at the middles of the sides of the selected node's visual element, if the node has its CanResize() function returning true.

One may not always want the whole Part to get the selection handle or all tool handles. Sometimes one wants to emphasize selection by highlighting a particular element within the part's visual tree. This can be achieved by setting the SelectionElementName property, and making sure the desired element has the same Name property value.

For more discussion about selection, see Selection.

Similarly the ResizeElementName and RotateElementName properties direct the corresponding ResizingTool and RotatingTool to operate on the particular GraphObject in the Part's visual tree with the given name. That includes both providing tool handles and actually modifying properties on that object.

Parts are not resizable or rotatable by default: you need to set Resizable and/or Rotatable to true.

For more discussion about tools, see Tools.

A Part may be positioned (or a Link may be routed) by a Layout. This will happen automatically if Layout or Layout are set. The default Layout will position any nodes that were not given explicit positions or location.

If you set IsLayoutPositioned to false, this part will not participate in any of the standard layouts, so it will not be moved by a layout or affect other parts in a layout. In order for the part to get a Location or position you will need to supply it explicitly.

As parts are added to or removed from a diagram, the Layout responsible for positioning the part is invalidated. This will cause the layout to be performed again in the near future, at the end of the transaction. This automatic layout invalidation also occurs as parts change their visibility (Visible) or their size (ActualBounds). If you do want there to be a Layout but you do not want an automatic layout to happen after removing parts (for example), you can set LayoutConditions not to include the Removed flag. In this particular case, you could set LayoutConditions to: LayoutConditions.LayoutStandard &amp; ~LayoutConditions.LayoutRemoved. It may also reasonable for your application to set it to None. Do not forget to consider applying the same conditions to links as well as to nodes and groups.

If you want to save the locations/positions of the parts in a diagram, it is commonplace to data bind the Location to a property on your node data with a TwoWay Binding. For example:

new Part(PanelLayoutHorizontal.Instance) { ... }
  .Bind("Location", "Loc", Point.Parse, Point.Stringify)

Then as the nodes are moved, whether manually by the user or automatically by a Layout, the model data is automatically updated with the location.

For more discussion about related topics, see Selection, Tools, and Permissions.

Parts that are templates should have no relationships with other Parts. Only real Parts that are in a Diagram can belong to Groups or have any Adornments. Only real Nodes in a Diagram can be connected with Links.

Constructors

Part()

Constructs an empty Part.

Declaration
public Part()
Remarks

The default Panel type is PanelLayoutPosition.

Part(PanelLayout)

Constructs an empty Part. The panel type must be one of the values permitted by Type.

Declaration
public Part(PanelLayout type)
Parameters
Type Name Description
PanelLayout type

if null, the default Panel type is PanelLayoutPosition.

Part(string)

Constructs an empty Part. The panel type can be a string describing one of the built PanelLayout types..

Declaration
public Part(string type)
Parameters
Type Name Description
string type

if the empty string, the default Panel type is PanelLayoutPosition.

Properties

Adornments

This read-only property returns a collection of the Adornments associated with this part.

Declaration
public IReadOnlyCollection<Adornment> Adornments { get; }
Property Value
Type Description
IReadOnlyCollection<Adornment>
Remarks

Templates should not have any adornments.

Category

Gets or sets the category of this part, typically used to distinguish different kinds of nodes or links.

Declaration
public string Category { get; set; }
Property Value
Type Description
string
Remarks

The initial value is an empty string, which is the default category. Any new value must be a string. This should not be set in templates.

When building Parts for node data or link data in a model, the Diagram will call GetCategoryForNodeData(TNodeData) or GetCategoryForLinkData(TLinkData) to get the category string for the data object. The diagram uses this value to look up a template in NodeTemplateMap, LinkTemplateMap or GroupTemplateMap. That template is copied to create the actual Part that is added to the diagram. The diagram will set this property to remember the category it used.

Note that the class of the new Part must be the same as the class of the original Part. For example, a Node cannot be replaced by a simple Part or vice-versa. Nor can a Link be replaced by a subclass of Link or vice-versa.

To change the category for a Part created for model data, call SetCategoryForNodeData(TNodeData, string) or SetCategoryForLinkData(TLinkData, string).

This property is also used to distinguish Adornments on a Part. In this scenario you create the Adornment, often indirectly by specifying a template, and set this property explicitly. For example, UpdateAdornments(Part) creates a resizing Adornment from the ResizeAdornmentTemplate and sets its category to be "Resizing". Changing the category of an existing Adornment will update any adorned part's association.

ContainingGroup

Gets or sets the Group of which this Part or Node is a member.

Declaration
public virtual Group ContainingGroup { get; set; }
Property Value
Type Description
Group
Remarks

This will be null if this is a top-level part.

You cannot set this property on a Link; it is set for you automatically based on the group memberships of the connected nodes. You cannot set this property on an Adornment at all.

A template should not be a member of any group.

See Also

ContainingGroupChanged

Gets or sets the function that is called after this Part has changed which Group it belongs to, if any.

Declaration
public Action<Part, Group, Group> ContainingGroupChanged { get; set; }
Property Value
Type Description
Action<Part, Group, Group>
Remarks

This is typically used to modify the appearance of the part. The first argument will be this Part. The second argument will be the old Group, or null if it had been a top-level part. The third argument will be the new Group, or null if it is now a top-level part.

If the value is a function, that function must not modify the part's containing Group. The containing Group has already been changed -- trying to change it again may produce undefined behavior.

The initial value is null -- no function is called.

Copyable

Gets or sets whether the user may copy this part.

Declaration
public bool Copyable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

See Also

Deletable

Gets or sets whether the user may delete this part.

Declaration
public bool Deletable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

See Also

Diagram

This read-only property returns the Diagram that this Part is in.

Declaration
public override Diagram Diagram { get; }
Property Value
Type Description
Diagram
Overrides
Remarks

This will be null if it is not in a Layer.

DragComputation

Gets or sets the function used to determine the location that this Part can be dragged to.

Declaration
public Func<Part, Point, Point, Point> DragComputation { get; set; }
Property Value
Type Description
Func<Part, Point, Point, Point>
Remarks

The first argument is a reference to the Part being dragged, the second argument is a Point describing the proposed location, and the third argument is a snapped location, if one was determined during dragging. It should return a Point that is the proposed new location.

By default this function is null and the DraggingTool uses the snapped location, if one was determined and if IsGridSnapEnabled is true, or the proposed location (the second argument) if not snapping to a grid.

In either case the DraggingTool will limit the proposed new location by MinLocation and MaxLocation.

The function, if supplied, must not have any side-effects.

An example that limits moving a Node to the current viewport:

Point StayInViewport(Part part, Point pt, Point gridpt) {
  var diagram = part.Diagram;
  if (diagram == null) return pt;
  // compute the area inside the viewport
  var v = diagram.ViewportBounds.SubtractMargin(diagram.Padding);
  // get the bounds of the part being dragged
  var bnds = part.ActualBounds;
  var loc = part.Location;
  // now limit the location appropriately
  var l = v.X + (loc.X - bnds.X);
  var r = v.Right - (bnds.Right - loc.X);
  var t = v.Y + (loc.Y - bnds.Y);
  var b = v.Bottom - (bnds.Bottom - loc.Y);
  if (l <= gridpt.X && gridpt.X <= r && t <= gridpt.Y && gridpt.Y <= b) return gridpt;
  var p = gridpt;
  if (diagram.ToolManager.DraggingTool.IsGridSnapEnabled) {
    // find a location that is inside V but also keeps the part's bounds within V
    var cw = diagram.Grid.GridCellSize.Width;
    if (cw > 0) {
      while (p.X > r) p.X -= cw;
      while (p.X < l) p.X += cw;
    }
    var ch = diagram.Grid.GridCellSize.Height;
    if (ch > 0) {
      while (p.Y > b) p.Y -= ch;
      while (p.Y < t) p.Y += ch;
    }
    return p;
  } else {
    p.X = Math.Max(l, Math.Min(p.X, r));
    p.Y = Math.Max(t, Math.Min(p.Y, b));
    return p;
  }
}

Note that for this functionality you will also probably want to set AutoScrollRegion to be a zero margin.

myDiagram.NodeTemplate =
  new Node { ..., DragComputation = StayInViewport }
See Also

Groupable

Gets or sets whether the user may group this part to be a member of a new Group.

Declaration
public bool Groupable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

The grouping command is implemented by GroupSelection() and depends on ArchetypeGroupData having been set to a node data object. A Group can be ungrouped by the user if you set Ungroupable to true.

See Also

HighlightedChanged

Gets or sets the function to execute when this IsHighlighted changes.

Declaration
public Action<Part> HighlightedChanged { get; set; }
Property Value
Type Description
Action<Part>
Remarks

This is typically used to modify the appearance of the part. This function must not highlight or unhighlight any parts.

If this property value is a function, it is called with one argument, this Part that whose IsHighlighted value changed. By default this property is null.

See Also

IsAnimated

Gets or sets whether this part may be animated.

Declaration
public bool IsAnimated { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

IsHighlighted

Gets or sets whether this Part is highlighted.

Declaration
public bool IsHighlighted { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

Highlighted parts may be shown with a different appearance by changing the brush or visibility of one or more of the GraphObjects within the part. One way of doing that is by using binding. Consider part of the definition of a Node template:

new Shape { ... }
  // Shape.Fill is bound to Node.Data.Color
  .Bind("Fill", "Color")
  // Shape.Stroke is red when Node.IsHighlighted is true, black otherwise
  .Bind(new Binding("Stroke", "IsHighlighted",
                    (h, _) => { return (bool)h ? "red" : "black"; }).OfElement())
See Also

IsInDocumentBounds

Gets or sets whether this Part is part of the document bounds.

Declaration
public bool IsInDocumentBounds { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true. A value of false causes ComputeBounds() to ignore this part. If the value is false, it is possible that user will not be able to scroll far enough to see this part, if the part's ActualBounds are outside of the DocumentBounds.

IsLayoutPositioned

Gets or sets whether a Layout positions this Node or routes this Link.

Declaration
public bool IsLayoutPositioned { get; set; }
Property Value
Type Description
bool
Remarks

This property affects the value of CanLayout().

The initial value is true, meaning that this part is laid out by the layout responsible for this Part. If this part is a member of a Group, it is the Layout, otherwise it is the Layout.

A value of false means that this part is not affected by and does not affect any automatic layout, so the LayoutConditions property is ignored. You will need to make sure that it has a real Location or Position value, or else the Part might not be visible anywhere in the diagram.

Another way of controlling when layouts are invalidated is by setting LayoutConditions or IsInitial or IsOngoing.

IsSelected

Gets or sets whether this Part is selected.

Declaration
public bool IsSelected { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

Selected parts typically are shown either with an Adornment or with a different appearance by changing the brush or visibility of one or more of the GraphObjects within the part.

Changing this value does not by itself raise any "ChangingSelection" and "ChangedSelection" DiagramEvents. Tools and the CommandHandler and methods such as Select(Part) do raise those DiagramEvents because they want to surround changes to this property with a single "ChangingSelection" DiagramEvent beforehand and a single "ChangedSelection" afterwards.

See Also

IsShadowed

Gets or sets whether this part will draw shadows.

Declaration
public bool IsShadowed { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

By default, setting this property to true will attempt to draw shadows only on the GraphObjects in this Part that appear to act as background objects, and not on GraphObjects that appear to be in front of other GraphObjects in the Part.

To finely control shadows, you may need to set ShadowVisible on elements of this Part, so that they explicitly do or do not get shadowed accordingly.

The color of the shadow is determined by ShadowColor. The opacity of the shadow color is multiplied by the opacity of the shadowed object's brush. So, for example, if you have a Panel with a Background that is "transparent", the shadow that is drawn for the panel will also be transparent.

The direction of the shadow that is cast is controlled by ShadowOffset, and is independent of the Scale. The sharpness of the shadow is controlled by ShadowBlur.

See Also

IsTopLevel

This read-only property is true when this part is not member of any Group node nor is it a label node for a Link.

Declaration
public bool IsTopLevel { get; }
Property Value
Type Description
bool
See Also

Key

This read-only property returns the Part's Model data key if it is in a Diagram and is backed by Model data; otherwise this returns the default key.

Declaration
public virtual object Key { get; }
Property Value
Type Description
object
See Also

Layer

This read-only property returns the Layer that this Part is in.

Declaration
public override Layer Layer { get; }
Property Value
Type Description
Layer
Overrides
Remarks

The value is the Layer that is named with the value of LayerName. If you want to change what Layer this Part is in, change the value of LayerName to refer to a different Layer.

This will be null if it has not yet been added to a Diagram, or if it has already been removed from a Diagram.

See Also

LayerChanged

Gets or sets the function to execute when this part changes layers.

Declaration
public Action<Part, Layer, Layer> LayerChanged { get; set; }
Property Value
Type Description
Action<Part, Layer, Layer>
Remarks

This is typically used to modify the appearance of the part. This function must not change the layer of this part by setting LayerName.

If this property value is a function, it is called with three arguments, this Part, the old Layer (may be null), and the new Layer (may be null). By default this property is null -- no function is called.

See Also

LayerName

Gets or sets the layer name for this part.

Declaration
public string LayerName { get; set; }
Property Value
Type Description
string
Remarks

The initial value is an empty string, which is the name of the default layer. The value of this property determines the value of Layer.

If this part is not yet in a Diagram, this value is used by Add(Part) to determine which Layer this part should go in. If no layer can be found with this name, it uses the default layer.

Changing the value of this property while it is already in a layer causes it to change layers if needed.

See Also

LayoutConditions

Gets or sets flags that control when the Layout that is responsible for this Part is invalidated.

Declaration
public LayoutConditions LayoutConditions { get; set; }
Property Value
Type Description
LayoutConditions
Remarks

The initial value is Standard, which causes the layout for this part to be invalidated when the part is added or removed or changes visibility or size.

Individual layout conditions include: Added, Removed, Shown, Hidden, and NodeSized.

This property is ignored when IsLayoutPositioned is false -- no operation on this Part will by itself cause the responsible Layout to be invalidated.

You can also control when layouts are invalidated is by setting IsInitial or IsOngoing.

Location

Gets or sets the position of this part in document coordinates, based on the LocationSpot in this part's LocationElement.

Declaration
public Point Location { get; set; }
Property Value
Type Description
Point
Remarks

Value must be of type Point. The initial value is Point(double.NaN, double.NaN). It is commonplace to data bind this property to some property on your model node data.

The value is related to the Position. For Parts, both are in document coordinates; setting one property will set the other property. By default both will have the same value. However, by setting either or both of LocationSpot and LocationElementName, the location will be determined by a spot in the LocationElement, a GraphObject that is in the visual tree of this Part. The Position will always refer to the point at the top-left corner of the whole part.

The MinLocation and MaxLocation limit the location of a part, not its position. Grid snapping will normally locate the location to be on grid points.

See Also

LocationElement

This read-only property returns the GraphObject that determines the location of this Part.

Declaration
public GraphObject LocationElement { get; }
Property Value
Type Description
GraphObject
Remarks

The value will be in the visual tree of this Part and is usually named with the value of LocationElementName.

LocationElementName

Gets or sets the name of the GraphObject that provides the location of this Part.

Declaration
public string LocationElementName { get; set; }
Property Value
Type Description
string
Remarks

This name determines the value of LocationElement. The actual Location also depends on the LocationSpot.

The initial value is an empty string, meaning the whole Part itself determines the location. If you want to use a particular GraphObject in the visual tree of this Part, set this property to be the Name of the element that you want to be the LocationElement.

See Also

LocationSpot

Gets or sets the location Spot of this Node, the spot on the LocationElement that is used in positioning this part in the diagram.

Declaration
public Spot LocationSpot { get; set; }
Property Value
Type Description
Spot
Remarks

Value must be of the type Spot. The initial value is Spot.TopLeft. The value must be a specific spot -- i.e. one for which IsSpot() is true.

It is commonplace to set this property to Spot.Center, so that the Location has a value corresponding to the point at the center of this Part's LocationElement element. But the Position of a Part is always at the top-left corner point of the ActualBounds.

See Also

MaxLocation

Gets or sets the maximum location of this Part to which the user may drag using the DraggingTool.

Declaration
public Point MaxLocation { get; set; }
Property Value
Type Description
Point
Remarks

Value must be of type Point. The initial value is (Infinity, Infinity), which imposes no position constraint. A X value of double.NaN causes ComputeMove(Part, Point, DraggingOptions) to use the part's current location's X value as the maximum, and similarly for double.NaN as the Y value.

See Also

MinLocation

Gets or sets the minimum location of this Part to which the user may drag using the DraggingTool.

Declaration
public Point MinLocation { get; set; }
Property Value
Type Description
Point
Remarks

Value must be of type Point. The initial value is (-Infinity, -Infinity), which imposes no position constraint. A X value of double.NaN causes ComputeMove(Part, Point, DraggingOptions) to use the part's current location's X value as the minimum, and similarly for double.NaN as the Y value.

See Also

Movable

Gets or sets whether the user may move this part.

Declaration
public bool Movable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

See Also

Reshapable

Gets or sets whether the user may reshape this part.

Declaration
public bool Reshapable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

See Also

Resizable

Gets or sets whether the user may resize this part.

Declaration
public bool Resizable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

If you set this to true you may also want to set ResizeElementName to the Named element that you want the user to resize. It is also commonplace to add a TwoWay Binding of that named element's DesiredSize in order to save to the model data the value that the user set via the ResizingTool.

See Also

ResizeAdornmentTemplate

Gets or sets the adornment template used to create a resize handle Adornment for this part.

Declaration
public Adornment ResizeAdornmentTemplate { get; set; }
Property Value
Type Description
Adornment
Remarks

This is used by the ResizingTool, ResizingTool.

If an Adornment is supplied, it is normally a PanelLayoutSpot panel that contains a Placeholder with some number of resize handles at the four corners or at the four side midpoints.

See Also

ResizeCellSize

Gets or sets the width and height multiples used when resizing.

Declaration
public Size ResizeCellSize { get; set; }
Property Value
Type Description
Size
Remarks

By default this property is the Size(double.NaN, double.NaN).

See Also

ResizeElement

This read-only property returns the GraphObject that should get resize handles when this part is selected.

Declaration
public GraphObject ResizeElement { get; }
Property Value
Type Description
GraphObject
Remarks

The value will be in the visual tree of this Part and is usually named with the value of ResizeElementName.

See Also

ResizeElementName

Gets or sets the name of the GraphObject that should get a resize handle when this part is selected.

Declaration
public string ResizeElementName { get; set; }
Property Value
Type Description
string
Remarks

The value of this property affects the value of ResizeElement. The initial value is an empty string, meaning the whole Part itself gets any resize handle.

See Also

Rotatable

Gets or sets whether the user may rotate this part.

Declaration
public bool Rotatable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is false.

If you set this to true you may also want to set RotateElementName to the Named element that you want the user to rotate. It is also commonplace to add a TwoWay Binding of that named element's Angle in order to save to the model data the value that the user set via the RotatingTool.

See Also

RotateAdornmentTemplate

Gets or sets the adornment template used to create a rotation handle Adornment for this part.

Declaration
public Adornment RotateAdornmentTemplate { get; set; }
Property Value
Type Description
Adornment
Remarks

This is used by the RotatingTool, RotatingTool.

This Adornment should not have a Placeholder in it, because the RotatingTool will position it away from the RotateElement at its Angle.

See Also

RotateElement

This read-only property returns the GraphObject that should get rotate handles when this part is selected.

Declaration
public GraphObject RotateElement { get; }
Property Value
Type Description
GraphObject
Remarks

The value will be in the visual tree of this Part and is usually named with the value of RotateElementName.

See Also

RotateElementName

Gets or sets the name of the GraphObject that should get a rotate handle when this part is selected.

Declaration
public string RotateElementName { get; set; }
Property Value
Type Description
string
Remarks

The value of this property affects the value of RotateElement. The initial value is an empty string, meaning the whole Part itself gets any rotate handle.

See Also

RotationSpot

Gets or sets the spot on the RotateElement that is used in rotating this part with the RotatingTool.

Declaration
public Spot RotationSpot { get; set; }
Property Value
Type Description
Spot
Remarks

Value must be of the type Spot. The value must be a specific spot -- i.e. one for which IsSpot() is true, or else Spot.Default.

If the value is Spot.Default, the RotatingTool uses the locationSpot if the RotateElement is equal to the LocationElement, otherwise it uses Spot.Center.

The initial value is Spot.Default.

See Also

Selectable

Gets or sets whether the user may select this part.

Declaration
public bool Selectable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

If you set this to true you may also want to set SelectionElementName to the Named element that you want to be adorned when the Part is selected.

See Also

SelectionAdorned

Gets or sets whether a selection adornment is shown for this part when it is selected.

Declaration
public bool SelectionAdorned { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

See Also

SelectionAdornmentTemplate

Gets or sets the Adornment template used to create a selection handle for this Part.

Declaration
public Adornment SelectionAdornmentTemplate { get; set; }
Property Value
Type Description
Adornment
Remarks

If this is null, depending on the class of this Part, the value of NodeSelectionAdornmentTemplate, GroupSelectionAdornmentTemplate, or LinkSelectionAdornmentTemplate is used instead.

It is commonplace to make use of a Placeholder in an Adornment for a Node, Group, or simple Part. The Placeholder represents the AdornedElement of the adorned Part. For Links, the Adornment must be of Type PanelLayoutLink.

See Also

SelectionChanged

Gets or sets the function to execute when this part is selected or deselected.

Declaration
public Action<Part> SelectionChanged { get; set; }
Property Value
Type Description
Action<Part>
Remarks

This is typically used to modify the appearance of the part. This function must not select or deselect any parts.

If this property value is a function, it is called with one argument, this Part that was selected or that became unselected. When it is called, the value of SkipsUndoManager is temporarily set to true. By default this property is null.

This function is called with SkipsUndoManager temporarily set to true, so that any changes to GraphObjects are not recorded in the UndoManager. You do not need to start and commit any transaction in this function.

See Also

SelectionElement

This read-only property returns the GraphObject that should get a selection handle when this part is selected.

Declaration
public GraphObject SelectionElement { get; }
Property Value
Type Description
GraphObject
Remarks

The value will be in the visual tree of this Part and is usually named with the value of SelectionElementName. When the SelectionElementName is unspecified, this whole Part is used as the "selection object".

See Also

SelectionElementName

Gets or sets the name of the GraphObject that should get a selection handle when this part is selected.

Declaration
public string SelectionElementName { get; set; }
Property Value
Type Description
string
Remarks

The value of this property affects the value of SelectionElement. The initial value is an empty string, meaning the whole Part itself gets any selection handle.

If no GraphObject has a Name that is this name, SelectionElement returns the whole Part.

See Also

ShadowBlur

Gets or sets the numerical value that describes the shadow's blur. Number must be non-negative and non-infinity.

Declaration
public float ShadowBlur { get; set; }
Property Value
Type Description
float
Remarks

A value of 0 would mean the shadow does not blur and larger numbers represent increasingly more blur. The total blur area is independent of the Part's area and can become quite large as this number is increased.

This value is not affected by scale. Default value is 4.

See Also

ShadowColor

Gets or sets the CSS string that describes a shadow color. Default is "gray".

Declaration
public string ShadowColor { get; set; }
Property Value
Type Description
string
Remarks

Brushes cannot be used for this property -- only strings.

The opacity of the shadow color is multiplied by the opacity of the shadowed object's brush. So, for example, if you have a Panel with a Background that is "transparent", the shadow that is drawn for the panel will also be transparent.

See Also

ShadowOffset

Gets or sets the X and Y offset of this part's shadow. This is only relevant if IsShadowed is true.

Declaration
public Point ShadowOffset { get; set; }
Property Value
Type Description
Point
Remarks

The initial value is (6, 6).

See Also

Text

Gets or sets a text string that is associated with this part.

Declaration
public string Text { get; set; }
Property Value
Type Description
string
Remarks

The initial value is an empty string. This value is often used for sorting.

TextEditable

Gets or sets whether the user may do in-place text editing on TextBlocks in this part that have Editable set to true.

Declaration
public bool TextEditable { get; set; }
Property Value
Type Description
bool
Remarks

The initial value is true.

See Also

ZOrder

Gets or sets the z-ordering position of this Part within its Layer.

Declaration
public double ZOrder { get; set; }
Property Value
Type Description
double
Remarks

Within the same layer, nodes with larger z-order values are placed in front of nodes with smaller z-order values. When the value is double.NaN the ordering is not specified. The default value is double.NaN.

When a Group has a z-order value of double.NaN, it is automatically placed behind its member nodes and links that also have no z-order. Such automatic ordering is not guaranteed if any nodes including the groups have a numeric z-order. If you do want to specify the z-order of nodes, you should also specify the z-order of their containing groups unless those groups are in different layers.

Methods

AddAdornment(string, Adornment)

Associate an Adornment with this Part, perhaps replacing any existing adornment of the same category.

Declaration
public void AddAdornment(string category, Adornment ad)
Parameters
Type Name Description
string category

a string identifying the kind or role of the given adornment for this Part.

Adornment ad

the new Adornment.

Remarks

Don't forget to set AdornedElement before calling this method.

This adds the Adornment to the Layer named by LayerName, normally "Adornment".

Adornments are also data bound to the same data that this Part has, if any. If the Adornment was already associated with a Part, it is unassociated with that old Part.

This method should not be called on templates.

CanCopy()

This predicate returns true if Copyable is true, if the layer's AllowCopy is true, and if the diagram's AllowCopy is true.

Declaration
public virtual bool CanCopy()
Returns
Type Description
bool

true if the user may copy this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanDelete()

This predicate returns true if Deletable is true, if the layer's AllowDelete is true, and if the diagram's AllowDelete is true.

Declaration
public virtual bool CanDelete()
Returns
Type Description
bool

true if the user may delete this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanEdit()

This predicate returns true if TextEditable is true, if the layer's AllowTextEdit is true, and if the diagram's AllowTextEdit is true.

Declaration
public virtual bool CanEdit()
Returns
Type Description
bool

true if the user may edit this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanGroup()

This predicate returns true if Groupable is true, if the layer's AllowGroup is true, and if the diagram's AllowGroup is true.

Declaration
public virtual bool CanGroup()
Returns
Type Description
bool

true if the user may group this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanLayout()

This predicate is called by Layout implementations to decide whether this Part should be positioned and might affect the positioning of other Parts.

Declaration
public virtual bool CanLayout()
Returns
Type Description
bool
Remarks

This is false if IsLayoutPositioned is false, if IsVisible() returns false, or if the part is in a temporary Layer.

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanMove()

This predicate returns true if Movable is true, if the layer's AllowMove is true, and if the diagram's AllowMove is true.

Declaration
public virtual bool CanMove()
Returns
Type Description
bool

true if the user may move this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanReshape()

This predicate returns true if Reshapable is true, if the layer's AllowReshape is true, and if the diagram's AllowReshape is true.

Declaration
public virtual bool CanReshape()
Returns
Type Description
bool

true if the user may reshape this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanResize()

This predicate returns true if Resizable is true, if the layer's AllowResize is true, and if the diagram's AllowResize is true.

Declaration
public virtual bool CanResize()
Returns
Type Description
bool

true if the user may resize this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanRotate()

This predicate returns true if Rotatable is true, if the layer's AllowRotate is true, and if the diagram's AllowRotate is true.

Declaration
public virtual bool CanRotate()
Returns
Type Description
bool

true if the user may rotate this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

CanSelect()

This predicate returns true if Selectable is true, if the layer's AllowSelect is true, and if the diagram's AllowSelect is true.

Declaration
public virtual bool CanSelect()
Returns
Type Description
bool

true if the user may select this part.

Remarks

This does not check IsReadOnly or IsReadOnly, but commands and tools should check those properties.

ClearAdornments()

Remove all adornments associated with this part.

Declaration
public void ClearAdornments()

EnsureBounds()

Measures if needed to make sure the MeasuredBounds and NaturalBounds are all real numbers, primarily to get the actual width and height.

Declaration
public virtual void EnsureBounds()
Remarks

ActualBounds will get a real width and height, but the x and y values may continue to be double.NaN if they were that way beforehand.

This is sometimes necessary to call when defining custom layouts or implementing virtualization, so that it can work with the actual size of the nodes.

For efficiency, do not call this method unnecessarily.

See Also

FindAdornment(string)

Find an Adornment of a given category associated with this Part.

Declaration
public Adornment FindAdornment(string category)
Parameters
Type Name Description
string category
Returns
Type Description
Adornment

Returns null if no such Adornment was found.

Remarks

Templates should not have any adornments.

FindCommonContainingGroup(Part)

Find the Group that perhaps indirectly contains both this part and another one.

Declaration
public Group FindCommonContainingGroup(Part other)
Parameters
Type Name Description
Part other
Returns
Type Description
Group

may be null

Remarks

If this is a Group and it contains the OTHER Part, return this. If the OTHER Part is a Group and it contains this Part, return that OTHER Part.

This returns null if the two parts are unrelated in the hierarchy of part membership. If non-null, the result is a Group.

If you want to find the Node that is the tree parent of two Nodes, call FindCommonTreeParent(Node).

FindSubGraphLevel()

Return how deep this part is in the hierarchy of nested Groups.

Declaration
public double FindSubGraphLevel()
Returns
Type Description
double
Remarks

For parts that have no ContainingGroup this returns zero.

If you want to know how deep a Node is in a tree structure, call FindTreeLevel().

FindTopLevelPart()

Gets the top-level Part for this part, which is itself when IsTopLevel is true.

Declaration
public Part FindTopLevelPart()
Returns
Type Description
Part

This will not return null.

Remarks

If this Part is a member of a Group, this returns the top-level Part for that Group. If this is a Node that is a label node for a labeled Link, this returns the top-level Part for that Link.

If this is a Node and you are searching for the root of the tree that this node is in, use FindTreeRoot().

GetDocumentBounds()

Returns the Rect in document coordinates for this object's bounds.

Declaration
public override Rect GetDocumentBounds()
Returns
Type Description
Rect

in document coordinates.

Overrides
Remarks

If this GraphObject is a Part, the rect will be identical to its ActualBounds.

See Also

InvalidateLayout(LayoutConditions)

Invalidate the Layout that is responsible for positioning this Part.

Declaration
public void InvalidateLayout(LayoutConditions condition = LayoutConditions.All)
Parameters
Type Name Description
LayoutConditions condition

the reason that the layout should be invalidated; if this argument is not supplied, any value of LayoutConditions other than None will allow the layout to be invalidated.

Remarks

If this part is in a Group, invalidate its Layout, if it has one. Otherwise invalidate the Layout.

But note that if IsLayoutPositioned is false, or if it is in a temporary Layer, or if it is not in a diagram or group, no layout is invalidated.

IsMemberOf(Part)

This predicate is true if this part is a member of the given Part, perhaps indirectly.

Declaration
public bool IsMemberOf(Part part)
Parameters
Type Name Description
Part part
Returns
Type Description
bool
Remarks

If the given part is a Group and this part is a member of the given group, this returns true. If this part is a Node and it is a label node for a link that is a member of the given group, this returns true. Otherwise this searches recursively any ContainingGroup of the given part.

A part cannot be contained by itself. A template should not be a member of any group.

If this is a Node and you want to find whether it is in a subtree whose root is a given Node, use IsInTreeOf(Node).

IsVisible()

This predicate is true if this Part can be seen.

Declaration
public virtual bool IsVisible()
Returns
Type Description
bool

true if Visible is true and if Visible is true.

Remarks

Parts that can be seen can be manipulated by the user, can take space in the document, or can take part in a layout, among many possibilities. Note that the value of this predicate can often be false even while Visible is true.

A Part is not seen if it is not Visible or if it is in a Layer that is not Visible.

If a Part is a member of a Group and the Group is not IsSubGraphExpanded, the part is not seen. (The containing Group might still be visible.)

If a Node is a "tree child" of a Node that is not IsTreeExpanded, the node is not seen. (The parent Node might still be visible.)

If a Link is connected to or from a Node that is not IsVisible() and is not a member of a Group that isVisible(), the link is not seen.

If a Node is a "link label" of a Link and that Link is not IsVisible(), the node is not seen.

This is different from IsVisibleElement(), which ignores whether the Layer is visible and just checks Visible up the chain of containing Panels.

If you want to know whether a Part is in the Diagram's viewport, try:

diagram.ViewportBounds.Contains(part.ActualBounds);

or:

diagram.ViewportBounds.Intersects(part.ActualBounds);

Move(Point, bool)

Move this part and any parts that are owned by this part to a new position.

Declaration
public virtual void Move(Point newpos, bool useLocation = false)
Parameters
Type Name Description
Point newpos

a new Point in document coordinates.

bool useLocation

true if you want to set the Location instead of the position. False by default.

Remarks

If this part is a Group, it also moves all of its members, recursively. If this part is a Link, it also moves all of its label nodes.

This method does not perform a transaction or start any animation.

Move(double, double, bool)

Move this part and any parts that are owned by this part to a new position.

Declaration
public void Move(double newx, double newy, bool useLocation = false)
Parameters
Type Name Description
double newx

a new X value in document coordinates.

double newy

a new Y value in document coordinates.

bool useLocation

true if you want to set the Location instead of the position. False by default.

Remarks

This just calls Move(Point, bool) without the caller having to allocate a new Point.

RemoveAdornment(string)

Remove any Adornment of the given category that may be associated with this Part.

Declaration
public void RemoveAdornment(string category)
Parameters
Type Name Description
string category

a string identifying the kind or role of the given adornment for this Part.

UpdateAdornments()

This is responsible for creating any selection Adornment (if this Part IsSelected) and any tool adornments for this part.

Declaration
public virtual void UpdateAdornments()

UpdateRelationshipsFromData()

Update all of the references to nodes in case they had been modified in the model without properly notifying the model by calling SetGroupKeyForNodeData(TNodeData, TNodeKey) or SetToKeyForLinkData(TLinkData, TNodeKey) or other similar methods.

Declaration
public virtual void UpdateRelationshipsFromData()
Remarks

This method does not conduct a transaction, so you need to start and commit one yourself.

This only updates the relationships between nodes, to have them reflect what is now declared in the model data. For example, in a GraphLinksModel if code has changed the value of the "To" property of a link data, calling this method on the corresponding Link would cause the link to connect with the Node whose data has the new key.

To update GraphObject properties that are data bound, call UpdateTargetBindings(string).

See Also

UpdateTargetBindings(string)

Re-evaluate all data bindings in this Part, in order to assign new property values to the GraphObjects in this visual tree based on this this object's Data property values.

Declaration
public override void UpdateTargetBindings(string srcprop = "")
Parameters
Type Name Description
string srcprop

An optional source data property name: when provided, only evaluates those Bindings that use that particular property; when not provided or when it is the empty string, all bindings are evaluated.

Overrides
Remarks

This method does nothing if Data is null.

It is better to call Set(object, string, object) to modify data properties, because that will both record changes for undo/redo and will update all bindings that make depend on that property.

To update relationships between nodes, call UpdateRelationshipsFromData().

See Also

Implements