Class Model<TNodeData, TNodeKey, TSharedData>
Models hold the essential data of a diagram, describing the basic entities and their properties and relationships without specifying the appearance and behavior of the Nodes and Links and Groups that represent them visually. Models tend to hold only relatively simple data, making them easy to persist by serialization as JSON formatted text.
Inheritance
Implements
Namespace: Northwoods.Go.Models
Assembly: Northwoods.GoDiagram.WinForms.dll
Syntax
[Serializable]
public class Model<TNodeData, TNodeKey, TSharedData> : IModel where TNodeData : class, new() where TNodeKey : IEquatable<TNodeKey>
Type Parameters
Name | Description |
---|---|
TNodeData | |
TNodeKey | |
TSharedData |
Remarks
Models hold simple data objects, not Parts such as Nodes or Links. Node data is normally represented in a Diagram by instances of Node, but they could be represented by simple Parts or by Groups. A Diagram constructs Parts for its Model's data by copying templates. Templates are Panels of GraphObjects that get some property values from the model data, accessible via the Data property, using data Binding. See Using Models and Data Binding for an introduction.
This Model class only supports holding an array of node data and interpreting properties on that data to be able to refer to them using unique key values. To support simple tree-structured graphs, use a TreeModel<TNodeData, TNodeKey, TSharedData>, which inherits from this class. To support links and grouping, use a GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>.
Each node data object is assumed to have a unique key value. The NodeKeyProperty property names the property on the node data whose value is the unique key for that node data object. The default value for this property is "Key". You should not have a TwoWay data binding on the node key property, because that might cause the property value to be set to a duplicate key value.
The key values type is specified by TNodeKey
.
If there are duplicate key values,
the model will automatically try to assign a new unique key value.
For example, one can define a graph consisting of just two nodes:
model.NodeDataSource = new List<MyNodeData> {
new MyNodeData { Key = "Alpha" },
new MyNodeData { Key = "Beta" }
};
This model cannot detect the modification of the NodeDataSource array or the modification of any node data object. If you want to add or remove node data from the NodeDataSource, call the AddNodeData(TNodeData) or RemoveNodeData(TNodeData) methods.
If you want to modify a node data object, it depends on whether the property you want to change is a structural property that the model needs to know about, or whether it is a property that is only used for data binding or other application-specific purposes.
For the former case, call the appropriate method, such as SetKeyForNodeData(TNodeData, TNodeKey), SetCategoryForNodeData(TNodeData, string), SetToKeyForLinkData(TLinkData, TNodeKey), or SetGroupKeyForNodeData(TNodeData, TNodeKey). These methods have names that start with "Set", "Add", "Insert", or "Remove".
For the latter case, when setting an application-specific property, typically for data binding, and to support undo/redo, call Set(object, string, object).
The CopyNodeData(TNodeData) method can be called to make a shallow copy of a node data object.
Each model raises ChangedEvents that you can follow by registering a listener via Changed. Read more at the Introduction page: Changed Events.
Each model comes with its own UndoManager that is initially not enabled. You will need to set IsEnabled to true in order for the UndoManager to record model changes and for your users to perform undo and redo.
You can temporarily turn off the recording of changes by setting SkipsUndoManager to true. A number of places within the system do that routinely in order to avoid recording temporary changes, so be sure to remember the original value beforehand and restore it afterwards. Note that in a ChangedEvent listener you may want to ignore events that happen when SkipsUndoManager is true.
One normally saves a diagram by just saving its model. If you can use JSON-formatted text, this is easy to do -- just call ToJson() to get the string representation of the model, and save that string. Load the diagram by replacing the Model with one created by calling the static function FromJson<T>(string):
myDiagram.Model = Model.FromJson<MyModel>(loadedString);
Note that JSON and other textual data formats cannot faithfully store all functions. ToJson() and FromJson<T>(string) do not try to save and load functional property values. You should arrange that all such functions, including event handlers, are established by your app. ToJson() and FromJson<T>(string) also cannot handle circular references; any sharing of references will be lost too.
Note that models also do not store the templates used by diagrams, nor any transient or temporary parts such as Adornments, nor any tools, nor any UndoManager state, nor any event listeners. These objects and all other properties of diagrams must be established by your app.
You can add any number of properties to the SharedData object, which is serialized and deserialized into JSON just like any other model data for nodes or links. However SharedData is associated with the model as a whole and does not depend on the existence of any node data or link data.
It is also easy to save the changes that were recorded in the most recent transaction. Call ToIncrementalJson(ChangedEvent) to generate a JSON-format string that holds the current state of modified data plus the keys of inserted or removed data. That method requires as an argument a ChangedEvent that represents a transaction that completed or an undo or a redo that just finished.
It is also possible to use such "incremental" JSON to modify an existing model. Call ApplyIncrementalJson(string), giving it a string generated by ToIncrementalJson(ChangedEvent), to modify this model by making all of the changes recorded in the JSON text. Note how this method is a regular instance method, whereas FromJson<T>(string) is a static function.
Constructors
Model()
Constructs an empty Model.
Declaration
public Model()
Model(Model<TNodeData, TNodeKey, TSharedData>)
Constructs a copy of a given Model, without copying the data.
Declaration
protected Model(Model<TNodeData, TNodeKey, TSharedData> model)
Parameters
Type | Name | Description |
---|---|---|
Model<TNodeData, TNodeKey, TSharedData> | model |
Model(IEnumerable<TNodeData>)
You probably don't want to call this constructor, because this class does not support links (relationships between nodes) or groups (nodes and links and subgraphs as nodes): instead, create instances of a subclass such as GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort> or TreeModel<TNodeData, TNodeKey, TSharedData> or a custom subclass of one of those.
Declaration
public Model(IEnumerable<TNodeData> nodedatasource)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<TNodeData> | nodedatasource | a collection containing objects to be represented by Parts. |
Properties
CopyNodeDataFunction
Gets or sets a function that makes a copy of a node data object.
Declaration
[JsonIgnore]
public Func<TNodeData, Model<TNodeData, TNodeKey, TSharedData>, TNodeData> CopyNodeDataFunction { get; set; }
Property Value
Type | Description |
---|---|
Func<TNodeData, Model<TNodeData, TNodeKey, TSharedData>, TNodeData> |
Remarks
You may need to set this property in order to ensure that a copied Node is bound to data that does not share certain data structures between the original node data and the copied node data. This property value may be null in order to cause CopyNodeData(TNodeData) to make a copy of an object. The default value is null.
The first argument to the function will be a node data object (potentially a Part's Data). The second argument to the function will be this Model itself.
It is common to implement a copying function when the node data has a list of data and that list needs to be copied rather than shared. Often the objects that are in the list also need to be copied.
DataFormat
Gets or sets the name of the format of the diagram data.
Declaration
public string DataFormat { get; set; }
Property Value
Type | Description |
---|---|
string |
Remarks
The default value is the empty string. The value must not be null. Use different values to prevent parts from one model to be copy/pasted or drag-and-dropped into another diagram/model.
IsReadOnly
Gets or sets whether this model may be modified, such as adding nodes.
Declaration
public bool IsReadOnly { get; set; }
Property Value
Type | Description |
---|---|
bool |
Remarks
By default this value is false. Setting the NodeDataSource to something that is not a true collection or is a read-only collection will cause this to be set to true.
Model methods and property setters do not heed this property. It is up to code that uses a model to check this property when it might want to prevent changes to the model.
MakeUniqueKeyFunction
Gets or sets a function that returns a unique key for a node data object.
Declaration
[JsonIgnore]
public Func<Model<TNodeData, TNodeKey, TSharedData>, TNodeData, TNodeKey> MakeUniqueKeyFunction { get; set; }
Property Value
Type | Description |
---|---|
Func<Model<TNodeData, TNodeKey, TSharedData>, TNodeData, TNodeKey> |
Remarks
This function is called by MakeNodeDataKeyUnique(TNodeData) when a node data object is added to the model, either as part of a new NodeDataSource or by a call to AddNodeData(TNodeData), to make sure the value of GetKeyForNodeData(TNodeData) is unique within the model.
The value may be null in order to cause MakeNodeDataKeyUnique(TNodeData) behave in the standard manner. (The default value is null.) You may want to supply a function here in order to make sure all of the automatically generated keys are in a particular format. Setting this property after setting NodeDataSource has no real effect until there is a call to AddNodeData(TNodeData).
If a node data object is already in the model and you want to change its key value, call SetKeyForNodeData(TNodeData, TNodeKey) with a new and unique key.
Name
Gets or sets the name of this model.
Declaration
public string Name { get; set; }
Property Value
Type | Description |
---|---|
string |
Remarks
The initial name is an empty string. The value must not be null.
NodeCategoryProperty
Gets or sets the name of the node data property that returns a string naming that data's category.
Declaration
public string NodeCategoryProperty { get; set; }
Property Value
Type | Description |
---|---|
string |
Remarks
The default value is the string "Category", meaning that it expects the data to have a property named "Category" if it cares to name a category. This is used by the diagram to distinguish between different kinds of nodes. The name must not be null. If the value is an empty string, GetCategoryForNodeData(TNodeData) will return an empty string for all node data objects.
If you want to set this property you must do so before using the model, and especially before you assign Model.
See Also
NodeDataSource
Gets or sets the collection of node data objects that correspond to Nodes, Groups, or non-Link Parts in the Diagram.
Declaration
public IEnumerable<TNodeData> NodeDataSource { get; set; }
Property Value
Type | Description |
---|---|
IEnumerable<TNodeData> |
Remarks
The initial value is an empty list.
For each object in the collection, GetKeyForNodeData(TNodeData) should return a key uniquely identifying the node data within the model. If it returns null or is a duplicate, this calls MakeNodeDataKeyUnique(TNodeData), to make sure the node data has a unique key. These key values may be used by other objects to refer to that particular node data object. If more than one node data object has the same key, there may be some confusion about which object to reference.
If you want to use a custom data property for holding the unique key value on a node data object,
you should set NodeKeyProperty before you set this NodeDataSource
property.
Adding or removing data from this collection will not notify this model or the diagram that there are any new nodes or that any nodes have been deleted. Instead you should call AddNodeData(TNodeData) or RemoveNodeData(TNodeData).
NodeKeyProperty
Gets or sets the name of the data property that returns a unique key for each node data object.
Declaration
public string NodeKeyProperty { get; set; }
Property Value
Type | Description |
---|---|
string |
Remarks
The default value is the name "Key", meaning that it expects the data to have a property named "Key" if it has a key value. The name must not be null or the empty string. You must set this property before assigning the NodeDataSource.
If you want to set this property you must do so before using the model, and especially before you assign Model.
See Also
SharedData
Gets an object that can hold programmer-defined property values for the model as a whole, rather than just for one node or one link.
Declaration
public TSharedData SharedData { get; set; }
Property Value
Type | Description |
---|---|
TSharedData |
Remarks
By default this is the default TSharedData
.
Most object classes cannot be serialized into JSON without special knowledge and processing at both ends. The ToJson() and FromJson<T>(string) methods automatically do such processing for numbers that are NaN and for objects that are of class Point, Size, Rect, Margin, Spot, Brush (but not for brush patterns), and for Geometry.
At the current time one cannot have a Diagram as a binding target. Calling Set(object, string, object) will work to change a property value, but there are no target bindings in any Diagrams to be updated. Because the binding mechanism is unavailable for this object, we recommend that when you want to save a model that you explicitly set properties on this object just before calling ToJson(). When loading a model, call FromJson<T>(string) and explicitly get the properties that you want to set on a Diagram.
SkipsUndoManager
Gets or sets whether ChangedEvents are not recorded by the UndoManager.
Declaration
[JsonIgnore]
public bool SkipsUndoManager { get; set; }
Property Value
Type | Description |
---|---|
bool |
Remarks
The initial and normal value is false. WARNING: while this property is true do not perform any changes that cause any previous transactions to become impossible to undo.
When this property is true, changing the Model or any data object does not call HandleChanged(ChangedEvent). Even when this property is true, transactions (such as calls to StartTransaction(string)) and undo/redo (such as calls to Undo()) are still delegated to the UndoManager.
You should set this to true only temporarily, and you should remember its previous value before setting this to true. When finishing the period for which you want the UndoManager to be disabled, do not blindly set this property to false. You should set this back to the value it had before you set it to true. For more permanent disabling of the UndoManager, set IsEnabled to false.
This property is also set when setting SkipsUndoManager. Setting this property does not raise a ChangedEvent.
UndoManager
Gets or sets the UndoManager for this Model.
Declaration
[JsonIgnore]
public UndoManager UndoManager { get; set; }
Property Value
Type | Description |
---|---|
UndoManager |
Remarks
The default UndoManager has its IsEnabled property set to false. If you want users to undo and redo, you should set that property to true once you have initialized the Diagram or its Model.
This property setter does not raise a ChangedEvent.
Methods
AddListItem(IList, object)
Add an item at the end of a data list that may be data bound by a Panel as its ItemList, in a manner that can be undone/redone and that automatically updates any bindings.
Declaration
public void AddListItem(IList coll, object val)
Parameters
Type | Name | Description |
---|---|---|
IList | coll | |
object | val | the new value to be pushed onto the array. |
Remarks
This also calls RaiseChangedEvent(ChangeType, string, object, object, object, object, object) to notify all listeners about the Insert.
If you want to add a new node or part to the diagram, call AddNodeData(TNodeData).
See Also
AddNodeData(TNodeData)
When you want to add a node or group to the diagram, call this method with a new data object.
Declaration
public void AddNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Remarks
This will add that data to the NodeDataSource and notify all listeners that a new node data object has been inserted into the collection.
To remove a node from the diagram, you can remove its data object by calling RemoveNodeData(TNodeData).
To add or remove an object or value from an item list, call InsertListItem(IList, int, object) or RemoveListItem(IList, int).
AddNodeData(IEnumerable<TNodeData>)
Add to this model all of the node data held in a collection of node data objects.
Declaration
public void AddNodeData(IEnumerable<TNodeData> coll)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<TNodeData> | coll | a collection of node data objects to add to the NodeDataSource |
ApplyIncrementalJson(string)
Modify this model by applying the changes given in an "incremental" model change in JSON format generated by ToIncrementalJson(ChangedEvent).
Declaration
public virtual void ApplyIncrementalJson(string s)
Parameters
Type | Name | Description |
---|---|---|
string | s | a string in JSON format containing modifications to be performed to the model |
Remarks
The expected properties of the argument are described at ToIncrementalJson(ChangedEvent). Incremental changes must be applied in the same order that the changes occurred in the original model.
All of the top-level properties in the JSON, such as NodeKeyProperty, must be the same as for this model. Note that if the model is a GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>, you will have to have set LinkKeyProperty to the name of a property, the same both in the Model as well as in the data that you pass to this method.
This conducts a transaction.
AssignAllDataProperties(object, object)
This safely calls Set(object, string, object) for each property other than a key property.
Declaration
public virtual void AssignAllDataProperties(object data, object props)
Parameters
Type | Name | Description |
---|---|---|
object | data | a data object |
object | props | an object holding various properties whose values are to be assigned to the data object |
Remarks
This does not delete any properties on the data object, although properties may be set to default if they are set that way on the props object.
Clear()
Clear out all references to any model data.
Declaration
public virtual void Clear()
Remarks
This also clears out the UndoManager, so this operation is not undoable. This method is called by Clear(); it does not notify any Diagrams or other listeners. This method does not unregister any Changed event listeners.
Instead of calling this method, you may prefer to set NodeDataSource to an empty collection. If this model is a GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>, you would also want to set LinkDataSource to a separate empty collection.
Commit(Action<Model<TNodeData, TNodeKey, TSharedData>>, string)
Starts a new transaction, calls the provided function, and commits the transaction.
Declaration
public void Commit(Action<Model<TNodeData, TNodeKey, TSharedData>> func, string tname = "")
Parameters
Type | Name | Description |
---|---|---|
Action<Model<TNodeData, TNodeKey, TSharedData>> | func | the function to call as the transaction body |
string | tname | a descriptive name for the transaction, or null to temporarily set SkipsUndoManager to true; if no string transaction name is given, an empty string is used as the transaction name |
Remarks
Code is called within a try-finally loop. If the function does not return normally, this rolls back the transaction rather than committing it. Example usage:
myModel.Commit(m => m.AddNodeData(new MyNodeData { Key = "Zeta" } ), "Added Node");
CommitTransaction(string)
Commit the changes of the current transaction.
Declaration
public bool CommitTransaction(string tname = null)
Parameters
Type | Name | Description |
---|---|---|
string | tname | a descriptive name for the transaction. |
Returns
Type | Description |
---|---|
bool | the value returned by CommitTransaction(string). |
Remarks
This just calls CommitTransaction(string).
ContainsNodeData(TNodeData)
Decide if a given node data object is in this model, using reference equality.
Declaration
public bool ContainsNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Returns
Type | Description |
---|---|
bool | true if it is a node data object in this model; false otherwise. |
Remarks
If you do not have a reference to the particular data object that is in the NodeDataSource, you may need to search for it by iterating through that collection, or by finding the desired Node or simple Part in a Diagram and getting that node's Data, or most likely by calling FindNodeDataForKey(TNodeKey).
CopyNodeData(TNodeData)
Make a copy of a node data object.
Declaration
public virtual TNodeData CopyNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Returns
Type | Description |
---|---|
TNodeData |
Remarks
This uses the value of CopyNodeDataFunction to actually perform the copy, unless that property is null. When it is null the default behavior is to just make a copy of the object via Clone() or via JSON serialization.
This does not modify the model -- the returned data object is not added to this model. This assumes that the data's constructor can be called with no arguments.
Models should not have any references to Diagrams or GraphObjects or Tools or Layouts or other objects that form a Diagram.
Warning: there should not be any cyclical references within the model data, unless you have supplied your own CopyNodeDataFunction that can handle cyclical references.
See Also
FindNodeDataForKey(TNodeKey)
Given a key, find the node data object in this model that uses the given value as its unique key.
Declaration
public TNodeData FindNodeDataForKey(TNodeKey key)
Parameters
Type | Name | Description |
---|---|---|
TNodeKey | key | a key. |
Returns
Type | Description |
---|---|
TNodeData | null if the key is not present in the model. |
See Also
FromJson<T>(string)
This static function parses a string in JSON format that was written by ToJson(), and then constructs, initializes, and returns a model with that information.
Declaration
public static T FromJson<T>(string s) where T : Model<TNodeData, TNodeKey, TSharedData>, new()
Parameters
Type | Name | Description |
---|---|---|
string | s | a string in JSON format containing all of the persistent properties of the model. |
Returns
Type | Description |
---|---|
T | the created model loaded with data from the given string. |
Type Parameters
Name | Description |
---|---|
T | the model type to deserialize into |
Remarks
Note that properties with values that are functions are not written out by ToJson(), so reading in such a model will require constructing such a model, initializing its functional property values, and explicitly passing it in as the second argument.
Typical usage:
var modelAsText = ...; // fetch the model in textual format from a database
myDiagram.Model = Model.FromJson<MyModel>(modelAsText);
GetCategoryForNodeData(TNodeData)
Find the category of a given node data, a string naming the node template or group template or part template that the Diagram should use to represent the node data.
Declaration
public string GetCategoryForNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Returns
Type | Description |
---|---|
string |
See Also
GetKeyForNodeData(TNodeData)
Given a node data object return its unique key: a number or a string.
Declaration
public TNodeKey GetKeyForNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Returns
Type | Description |
---|---|
TNodeKey |
Remarks
This returns the default TNodeKey
if there is no key value.
It is possible to change the key for a node data object by calling SetKeyForNodeData(TNodeData, TNodeKey).
See Also
InsertListItem(IList, int, object)
Add an item to a data list that may be data bound by a Panel as its ItemList, given a new data value and the index at which to insert the new value, in a manner that can be undone/redone and that automatically updates any bindings.
Declaration
public void InsertListItem(IList list, int idx, object val)
Parameters
Type | Name | Description |
---|---|---|
IList | list | |
int | idx | the zero-based list index where the new value will be inserted; use -1 to push the new value on the end of the list. |
object | val | the new value to be inserted into the list. |
Remarks
This also calls RaiseChangedEvent(ChangeType, string, object, object, object, object, object) to notify all listeners about the Insert.
If you want to add a new node or part to the diagram, call AddNodeData(TNodeData).
See Also
MakeNodeDataKeyUnique(TNodeData)
This method is called when a node data object is added to the model to make sure that GetKeyForNodeData(TNodeData) returns a unique key value.
Declaration
public void MakeNodeDataKeyUnique(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Remarks
The key value should be unique within the set of data managed by this model: NodeDataSource. If the key is already in use, this will assign an unused key to the NodeKeyProperty property on the data when possible.
If you want to customize the way in which node data gets a unique key, you can set the MakeUniqueKeyFunction functional property.
If the node data object is already in the model and you want to change its key value, call SetKeyForNodeData(TNodeData, TNodeKey) and give it a new unique key value.
MergeNodeData(IEnumerable<TNodeData>)
Take a collection of node data objects and update NodeDataSource without replacing the collection and without replacing any existing node data objects that are identified by key.
Declaration
public void MergeNodeData(IEnumerable<TNodeData> coll)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<TNodeData> | coll |
Remarks
For node data objects that have the same key value, this makes calls to Set(object, string, object) to update the existing node data object. For new keys, this calls the object's Clone method to copy the data and then AddNodeData(TNodeData) to add a new node to the model. For existing nodes that have keys that are not present in the given collection, this calls RemoveNodeData(TNodeData) to remove the existing node from the model.
This method will error if a new key is added and the TNodeData type is not ICloneable.
This method is typically used when GoDiagram is being used within an application that is maintaining state related to the diagram model. When state is updated, this method can be called to keep the GoDiagram model synchronized. Any updates to the data should use new references since this method will use reference equality to check if a node data object needs to be updated.
This method does not conduct a transaction.
RaiseChangedEvent(ChangeType, string, object, object, object, object, object)
Call this method to notify that the model or its objects have changed. This constructs a ChangedEvent and calls all Changed listeners.
Declaration
public void RaiseChangedEvent(ChangeType change, string propertyname, object obj, object oldval, object newval, object oldparam = null, object newparam = null)
Parameters
Type | Name | Description |
---|---|---|
ChangeType | change | specifies the general nature of the change; typically the value is Property. |
string | propertyname | names the property that was modified. |
object | obj | the object that was modified, typically a GraphObject, Diagram, or a Model<TNodeData, TNodeKey, TSharedData>. |
object | oldval | the previous or older value. |
object | newval | the next or newer value. |
object | oldparam | an optional value that helps describe the older value. |
object | newparam | an optional value that helps describe the newer value. |
RaiseDataChanged(object, string, object, object, object, object)
Call this method to notify about a data property having changed value.
Declaration
public void RaiseDataChanged(object data, string propertyname, object oldval, object newval, object oldparam = null, object newparam = null)
Parameters
Type | Name | Description |
---|---|---|
object | data | the data object whose property changed value. |
string | propertyname | the name of the property, or a function that takes an Object and returns the property value. |
object | oldval | the previous or old value for the property. |
object | newval | the next or new value for the property. |
object | oldparam | an optional value additionally describing the old value. |
object | newparam | an optional value additionally describing the new value. |
Remarks
This constructs a ChangedEvent and calls all Changed listeners.
You should call this method only if the property value actually changed. This method is called by Set(object, string, object).
RemoveListItem(IList, int)
Remove an item from a data list that may be data bound by a Panel as its ItemList, given the index at which to remove a data value, in a manner that can be undone/redone and that automatically updates any bindings.
Declaration
public void RemoveListItem(IList list, int idx = -1)
Parameters
Type | Name | Description |
---|---|---|
IList | list | |
int | idx | the zero-based list index of the data item to be removed from the list; if not supplied it will remove the last item of the list. |
Remarks
This also calls RaiseChangedEvent(ChangeType, string, object, object, object, object, object) to notify all listeners about the Remove.
If you want to remove a node from the diagram, call RemoveNodeData(TNodeData).
Note that there is no version of this method that takes an item value instead of an index into the list. Because item lists may hold any value, including numbers and strings, there may be duplicate entries with that value in the list. To avoid ambiguity, removing an item from an list requires an index.
See Also
RemoveNodeData(TNodeData)
When you want to remove a node or group from the diagram, call this method with an existing data object.
Declaration
public void RemoveNodeData(TNodeData nodedata)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
Remarks
This will remove that data from the NodeDataSource and notify all listeners that a node data object has been removed from the collection.
If you do not have a reference to the particular data object that is in the NodeDataSource, you may need to search for it by iterating through that collection, or by finding the desired Node or simple Part in a Diagram and getting that node's Data, or most likely by calling FindNodeDataForKey(TNodeKey).
Removing a node data from a model does not automatically remove any connected link data from the model. Removing a node data that represents a group does not automatically remove any member node data or link data from the model.
To add a node to the diagram, you can add its data object by calling AddNodeData(TNodeData).
To add or remove an object or value from an item list, call InsertListItem(IList, int, object) or RemoveListItem(IList, int).
RemoveNodeData(IEnumerable<TNodeData>)
Remove from this model all of the node data held in a collection of node data objects.
Declaration
public void RemoveNodeData(IEnumerable<TNodeData> coll)
Parameters
Type | Name | Description |
---|---|---|
IEnumerable<TNodeData> | coll | a collection of node data objects to remove from the NodeDataSource |
RollbackTransaction()
Rollback the current transaction, undoing any recorded changes.
Declaration
public bool RollbackTransaction()
Returns
Type | Description |
---|---|
bool | the value returned by RollbackTransaction(). |
Remarks
This just calls RollbackTransaction().
Set(object, string, object)
Change the value of some property of a node data, a link data, an item data, or the SharedData, given a string naming the property and the new value, in a manner that can be undone/redone and that automatically updates any bindings.
Declaration
public virtual void Set(object data, string propname, object val)
Parameters
Type | Name | Description |
---|---|---|
object | data | an object typically the value of a Data and represented by a Node, Link, Group, simple Part, or item in a ItemList; or this model's SharedData. |
string | propname | a string that is not null or the empty string. |
object | val | the new value for the property. |
Remarks
This gets the old value of the property; if the value is the same as the new value, no side-effects occur. This calls RaiseDataChanged(object, string, object, object, object, object) to notify about the change.
Note that it is insufficient to modify an item list (for example by pushing a new item onto the list) and
then call Set(data, "Items", data.Items)
because the value of
data.Items
is still the same reference.
Instead you will want to call InsertListItem(IList, int, object), AddListItem(IList, object), or RemoveListItem(IList, int).
If you modify the property that is the NodeKeyProperty, this will call SetKeyForNodeData(TNodeData, TNodeKey).
If you modify the property that is the NodeCategoryProperty or the LinkCategoryProperty, this will call SetCategoryForNodeData(TNodeData, string) or SetCategoryForLinkData(TLinkData, string). But if the category might change, Binding sources should not be (or depend in a conversion function on) the category of the data, because then some bindings might be evaluated before or after the category has been changed.
See Also
SetCategoryForNodeData(TNodeData, string)
Change the category of a given node data, a string naming the node template or group template or part template that the Diagram should use to represent the node data.
Declaration
public void SetCategoryForNodeData(TNodeData nodedata, string cat)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
string | cat | Must not be null. |
Remarks
Changing the node template for a node data will cause the existing Node, Group, or Part to be replaced with a new instance of the same class created by copying the new node template and applying any data-bindings. That means that the templates in the NodeTemplateMap or GroupTemplateMap must be instances of the same class -- one cannot convert a Node into a Group or vice-versa by setting the category.
Binding sources should not be (or depend in a conversion function on) the category of the data if you might be modifying the category, because then some bindings might be evaluated before or after the category has been changed.
See Also
SetKeyForNodeData(TNodeData, TNodeKey)
Change the unique key of a given node data that is already in this model.
Declaration
public void SetKeyForNodeData(TNodeData nodedata, TNodeKey key)
Parameters
Type | Name | Description |
---|---|---|
TNodeData | nodedata | an object represented by a node, group, or non-link. |
TNodeKey | key |
Remarks
The new key value must be unique -- i.e. not in use by another node data object. You can call FindNodeDataForKey(TNodeKey) to check if a proposed new key is already in use.
This operation will check all data objects in the model and replace all references using the old key value with the new one.
If this is called on a node data object that is not (yet) in this model, this unconditionally modifies the property to the new key value.
See Also
StartTransaction(string)
Begin a transaction, where the changes are held by a Transaction object in the UndoManager.
Declaration
public bool StartTransaction(string tname = null)
Parameters
Type | Name | Description |
---|---|---|
string | tname | a descriptive name for the transaction. |
Returns
Type | Description |
---|---|
bool | the value returned by StartTransaction(string). |
Remarks
This just calls StartTransaction(string).
See Also
ToIncrementalData(ChangedEvent)
Produce an object representing the changes in the most recent Transaction.
Declaration
public Model<TNodeData, TNodeKey, TSharedData>.IncrementalData ToIncrementalData(ChangedEvent e)
Parameters
Type | Name | Description |
---|---|---|
ChangedEvent | e | a Transaction ChangedEvent for which IsTransactionFinished is true |
Returns
Type | Description |
---|---|
Model<TNodeData, TNodeKey, TSharedData>.IncrementalData | returns either null if no changes occurred, or an object containing incremental model changes for the given Transaction |
Remarks
The structure of the object follows the same format as the JSON output from ToIncrementalJson(ChangedEvent).
Note that these incremental changes include the results of undo and redo operations.
For GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>s, this method requires that LinkKeyProperty is not an empty string.
Any node or link data objects contained in the "Modified..." properties will be deep copies of the data in the model. When using this method, we suggest all data classes implement a Clone method such that faithful copies are made in the expected manner.
This method is most commonly used when GoDiagram must communicate with some external data source and maintain integrity between the two while avoiding serialization/deserialization.
myDiagram.ModelChanged += (object sender, ChangedEvent e) => {
if (e.IsTransactionFinished) {
var dataChanges = e.Model.ToIncrementalData(e);
... update application state/save to database ...
}
};
See Also
ToIncrementalJson(ChangedEvent)
Produce a JSON-format string representing the changes in the most recent Transaction.
Declaration
public string ToIncrementalJson(ChangedEvent e)
Parameters
Type | Name | Description |
---|---|---|
ChangedEvent | e | a Transaction ChangedEvent for which IsTransactionFinished is true |
Returns
Type | Description |
---|---|
string |
Remarks
This writes out JSON for a model, but recording only changes in the given Transaction. Instead of the "NodeDataSource" property (and "LinkDataSource" property for GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>s), this will have "Inserted...", "Modified...", and "Removed..." properties.
The "ModifiedNodeData" collection holds node data objects. The "InsertedNodeKeys" and "RemovedNodeKeys" collections hold keys of data, not whole objects, that have been added and/or deleted. The "SharedData" property holds the SharedData object, if it was modified.
Note that it is entirely plausible for the same object be in or referenced by all three collections, because a single Transaction can include adding a node, modifying it, and removing it.
The purpose of this method is to make it easier to send incremental changes to the server/database, instead of sending the whole model. Whereas it has always been easy to perform "batch" updates or "file saves":
myDiagram.ModelChanged += (object sender, ChangedEvent e) => {
if (e.IsTransactionFinished) {
var json = e.Model.ToJson();
// save the whole model upon each transaction completion or undo/redo
... send to server/database ...
}
};
You can now easily send "incremental" updates:
myDiagram.ModelChanged += (object sender, ChangedEvent e) => {
if (e.IsTransactionFinished) {
var json = e.Model.ToIncrementalJson(e);
// record each Transaction as a JSON-format string
... send to server/database ...
}
};
Note that these incremental changes include the results of undo and redo operations. Also, when you might call ApplyIncrementalJson(string), you will need to disable your Changed listener, so that it does not send spurious changes to your database during the process of applying incremental changes from the database.
For GraphLinksModel<TNodeData, TNodeKey, TSharedData, TLinkData, TLinkKey, TPort>s, this method requires that LinkKeyProperty is not an empty string. The incremental JSON for GraphLinksModels will include "ModifiedLinkData", "InsertedLinkKeys", and "RemovedLinkKeys" properties.
The same restrictions on data property names and data property values apply to this method as they do to ToJson().
ToJson()
Generate a string representation of the persistent data in this model, in JSON format, that can be read in later with a call to FromJson<T>(string).
Declaration
public string ToJson()
Returns
Type | Description |
---|---|
string | a string in JSON format containing all of the persistent properties of the model. |
Remarks
Functions are not able to be written in JSON format, so any properties that have function values will not be saved in the JSON string.
There must not be any circular references within the model data. Any sharing of object references will be lost in the written JSON.
The ToJson() and FromJson<T>(string) methods automatically process numbers that are NaN and objects that are of class Point, Size, Rect, Margin, Spot, Brush (but not for brush patterns), and for Geometry. However, we recommend that you use Binding converters (static functions named "Parse" and "Stringify") to represent Points, Sizes, Rects, Margins, Spots, and Geometries as string values in your data, rather than as Objects. This makes the JSON text smaller and simpler and easier to read.
Note that this is a method on the Model<TNodeData, TNodeKey, TSharedData> class. It cannot render unmodeled Parts such as the background grid or any Parts that you have added directly to a Diagram.
Typical usage:
var modelAsText = myDiagram.Model.ToJson();
// now save this text string by sending it to your database
UpdateTargetBindings(object, string)
Find a Part corresponding to the given data and call its UpdateTargetBindings(string) method, in each Diagram that uses this Model.
Declaration
public void UpdateTargetBindings(object data, string srcpropname = "")
Parameters
Type | Name | Description |
---|---|---|
object | data | The data object in this model that was modified. |
string | srcpropname | If not present or the empty string, update all bindings on the target Part or item Panel otherwise update only those bindings using this source property name. |
Remarks
Caution: setting a data property without calling Set(object, string, object) and then calling this UpdateTargetBindings method will update GraphObjects that are bound to the property, but such data settings will not be recorded in the UndoManager and therefore will not be undone/redone, causing an inconsistency between the GraphObjects and the part data.
Events
Changed
Register or unregister an event handler that is called when there is a ChangedEvent.
Declaration
public event EventHandler<ChangedEvent> Changed
Event Type
Type | Description |
---|---|
EventHandler<ChangedEvent> |
Remarks
This registration does not raise a ChangedEvent. In case a Diagram's Model may be replaced, you may prefer using ModelChanged instead.
Event listeners are not written out by ToJson().
Do not add or remove Changed listeners during the execution of a Changed listener.