Interface IDiagramModel
- Namespace
- StockSharp.Xaml.Diagram.GXDiagram.Model
- Assembly
- StockSharp.Xaml.Diagram.dll
All diagram models implement this interface or an interface that inherits from this interface.
public interface IDiagramModel
- Extension Methods
Remarks
This is reponsible for defining relationships between nodes, involving links and grouping.
It does not know about any FrameworkElement
s
(including Diagram or DiagramPanel or Part).
It just knows about .NET CLR objects as data of type object or about more specific types
when instantiating one of the generic DiagramModel classes.
It is vaguely analogous to a CollectionView
, providing additional organization of the source data.
It defines a graph from the data instead of imposing a total ordering on it and filtering/sorting/grouping it.
It also supports two-pass copying of existing data and undo/redo support via an UndoManager.
There are four categories of members in this interface: updating, navigation, modification, and miscellaneous. The updating methods need to be called when there has been a change to the data, so that the model can be kept up-to-date with the data. The navigation methods support examining the diagram and traversing the graph defined by the nodes and links in the diagram. The modification methods are used to alter the diagram. The miscellaneous methods and properties include support for model change notification, for undo/redo, for edits, and for data transfer. Additional categories of members exist in each of the model classes.
The most important member of this interface is the NodesSource property, the collection of node data defining the graph. You will need to set it before anything can be seen in your Diagram. The model will look at each node data in that collection to discover the relationships that will form the graph. The methods and properties for discovering a graph from the data depend on the kind of model, so they are not part of this interface.
As data is added or removed from the model, or as data is modified, the graph implied by the data changes. Whenever the data is modified, the model must be notified. The model interfaces (both this interface and more specific interfaces inheriting from this interface) have a category of methods for being notified of data changes. This basic interface includes methods such as DoNodeAdded(object), DoNodeRemoved(object), and DoNodeKeyChanged(object). More specific kinds of models have additional methods, such as: StockSharp.Xaml.Diagram.GXDiagram.Model.ITreeModel.DoParentNodeChanged(System.Object), StockSharp.Xaml.Diagram.GXDiagram.Model.IConnectedModel.DoToNodeKeyRemoved(System.Object,System.Object), DoLinkAdded(object), DoMemberNodeKeysChanged(object), and DoGroupNodeChanged(object). Updating methods have names that start with "Do".
Of course if your data is unchanging, neither by application code nor by the user, you will not need to be concerned about keeping the model up-to-date. But if your data might change, .NET provides some standard interfaces for change notification that you should use if you want successful data binding.
The INotifyPropertyChanged
interface (in the
System.ComponentModel
namespace) is commonly used for
notification of property changes. The diagram model classes automatically
register themselves as INotifyPropertyChanged.PropertyChanged
event
listeners for each of the data objects that are in the NodesSource
collection so that they can be updated if a model-relevant property changes
in a data object.
We suggest that you have your node data class implement this interface,
but that you use the ModelChangedEventArgs class for event arguments
instead of PropertyChangedEventArgs
.
In addition, Microsoft recommends implementing the INotifyCollectionChanged
interface (in the System.Collections.Specialized
namespace) for providing
change notification of collection objects.
.NET offers the ObservableCollection<T>
class as a standard
collection that implements INotifyCollectionChanged
.
So if the collection you supply as the value of NodesSource implements
this interface, the model will automatically call the DoNodeAdded(object)
and DoNodeRemoved(object) methods for you.
Similarly, for the data properties that are expected to be collections,
(such as the collection of tree children nodes for a data node in the tree model),
we suggest you use ObservableCollection<T>
.
Note that the optional data classes that we provide for your use, if you do not already
have your own data classes, implement INotifyPropertyChanged
and make use
of ObservableCollection<T>
.
An example is StockSharp.Xaml.Diagram.GXDiagram.Model.TreeModelNodeData`1.
The generic model classes have a parameterized type, NodeType
,
that denotes the type of the node data that it contains.
That of course is the required type of each item in the NodesSource collection.
Furthermore, all of the methods that operate on node data take and/or return that type.
This design provides for better type checking at compile time and potentially
better performance at run time.
But IDiagramModel and its subinterfaces are not generic.
Their methods all take and/or return data of type Object
instead of a
parameterized type.
This "universality" is necessary because the diagram control is not a generic class.
Unlike most controls that bind to a list of items, diagrams involve relationships between the items that are much more general than just the order in the list. This is achieved by interpreting some property values as "references" to other data. Such references might be implemented as .NET CLR references (i.e. pointers). However, it is also common to use other values, such as strings or numbers, as the references. Such a scheme requires being able to identify each data object with a unique value.
The generic model class have another parameterized type, NodeKey
,
that denotes the type of the values that refer to node data.
When the abstract references are actually .NET CLR references, the NodeKey
type will be the same as the NodeType
type.
But more often the NodeKey
will be something like String
or int
.
Normally the expectation is that the key value for each node data does not change. However, the models do support such a circumstance -- make sure the DoNodeKeyChanged(object) method is called right after changing a node's key.
The FindNodeByKey(object) method is useful for finding a node data given its key. To find out if a node data is in the NodesSource collection, call the IsNodeData(object) predicate.
The models have a number of methods that are useful for examining or navigating. These method names tend to start with "Get" or "Is". For "link" relationships, the following methods apply to all models: IsLinked(object, object, object, object), GetFromNodesForNode(object), GetToNodesForNode(object), GetConnectedNodesForNode(object). Particular kinds of models have additional methods for traversing graphs, such as: StockSharp.Xaml.Diagram.GXDiagram.Model.ITreeModel.GetChildrenForNode(System.Object), GetLinksBetweenNodes(object, object, object, object), GetToNodeForLink(object), GetLabelNodeForLink(object), GetMemberNodesForGroup(object), and GetGroupForNode(object). Note that the models will have similar protected (not public) methods that actually implement the corresponding behavior on the data. There will be virtual so that your model implementation can customize or optimize how the method performs the operation.
The models also have methods for modifying. These method names start with "Modify", "Add", or "Remove". For nodes, there are AddNode(object) and RemoveNode(object). For links, there are AddLink(object, object, object, object) and RemoveLink(object, object, object, object). Furthermore, particular kinds of models have additional methods for changing relationships, such as: StockSharp.Xaml.Diagram.GXDiagram.Model.ITreeModel.AddChildNodeKey(System.Object,System.Object), StockSharp.Xaml.Diagram.GXDiagram.Model.IConnectedModel.AddFromNodeKey(System.Object,System.Object), SetLinkLabel(object, object), RemoveMemberNodeKey(object, object), and SetGroupNode(object, object). Note that the models will have similar protected (not public) methods that actually implement the corresponding behavior on the data. There will be virtual so that your model implementation can customize or optimize how the method performs the modification.
Finally, there is the Modifiable property, that should disable user actions that would modify the model, and that causes errors when you call a model-modifying method anyway.
Models support a two-pass copying process. A single pass copy is insufficient because some "references" cannot be made before all objects have been copied -- those references need to be fixed-up afterwards, in a second pass. Let's say that we have two objects to be copied, A and B, and that A has a string property that refers to B by its name, "B". After making the two copied objects, A2 and B2, A2's reference will typically still be "B". The second copy pass will operate on A2 and give it a chance to look for the original "B" data, to find the copied B2 data, and to change A2's reference to be "B2".
The principal copying method is AddCollectionCopy(IDataCollection, ICopyDictionary). This first makes copies of all the data to be copied, and then iterates over them again, fixing up the references. You may need to override protected virtual methods whose names start with "Copy" in order to correctly construct copies of your data in the first pass, and in order to correctly fix references to other data in the second pass.
Even after the two-pass copying process has finished, there may still be unresolved references. ClearUnresolvedReferences()
For convenience in making a copy of a node and adding it to the model, there is also the AddNodeCopy(object) method.
Depending on the application, not all relationships should be possible.
Models provide support for link relationships with the IsLinkValid(object, object, object, object) method.
There are more specific model predicates for IsRelinkValid
:
IsRelinkValid(object, object, object, object, object), StockSharp.Xaml.Diagram.GXDiagram.Model.IConnectedModel.IsRelinkValid(System.Object,System.Object,System.Object,System.Object),
and StockSharp.Xaml.Diagram.GXDiagram.Model.ITreeModel.IsRelinkValid(System.Object,System.Object,System.Object,System.Object).
IsMemberValid(object, object) offers similar support for the
group-member relationship in IGroupsModel.
The diagram control uses these methods for deciding which user actions
are permissible.
The model classes add support for customizing these methods.
Each model is not only a consumer of events on its data but is also a generator Changed events, to allow model consumers such as the diagram control to keep themselves up-to-date with the model. StockSharp.Xaml.Diagram.GXDiagram.Model.ModelChange is an enumeration that lists all of the kinds of changes that can happen to the predefined model classes. Whenever there is a change to a model, the code calls RaiseChanged(ModelChangedEventArgs) or a similar method to notify model consumers. The IsModified property is automatically set to true as Changed events are raised.
Each model also supports undo and redo, using an UndoManager that records Changed events. Because ModelChangedEventArgs also implements StockSharp.Xaml.Diagram.GXDiagram.Model.IUndoableEdit, it is very easy for the undo manager to remember the changes in a manner that makes them easy to undo or redo. But note that the UndoManager property is initially null; you will need to set this property before any actions can be recorded and then undone. When you want to make transient changes that you do not want to be recorded by the undo manager, you can temporarily set SkipsUndoManager to true.
As you add state to your data or to your model, you may need to add code that implements state changing as needed for undo and redo. This can be done either by overriding a model method or a data method if the data implements IChangeDataValue.
A single user gesture or command may result in many model/data changes. These all want to be treated as a single undo-able action. You can group such changes together by calling StartTransaction(string) and CommitTransaction(string). If after a StartTransaction(string) you don't want to commit the changes, you can call RollbackTransaction(), which not only ends the transaction but also automatically "undoes" all of the changes since the call to StartTransaction(string).
Properties
DataFormat
Gets or sets the format of this model's data.
string DataFormat { get; set; }
Property Value
- string
By default this is the fully qualified name of this model type.
Remarks
This string is used by clipboard and drag-and-drop operations to distinguish between different and presumably incompatible data sources. You may wish to provide different values in order to prevent data from being transferred to other applications that are using the same model class.
IsChangingModel
This property is true during a call to ChangeModel(ModelChangedEventArgs, bool), indicating a change happening due to an undo or a redo.
bool IsChangingModel { get; }
Property Value
IsInTransaction
True if there is an UndoManager and a transaction has been started.
bool IsInTransaction { get; }
Property Value
IsModified
Gets or sets whether this model is considered changed from an earlier state.
bool IsModified { get; set; }
Property Value
- bool
true if this model has been marked as having been modified, if the UndoManager has recorded any changes, or if an undo has been performed without a corresponding redo.
Modifiable
Gets or sets whether various model-changing methods are enabled.
bool Modifiable { get; set; }
Property Value
- bool
By default this value is false.
Remarks
When false, this property disables methods named "Add...", "Modify...", or "Remove...".
But note that this property does not and cannot affect the "modifiability" or "read-only"-ness of model data, since the data classes may have no knowledge about this model class and this property.
Name
A name for this model.
string Name { get; set; }
Property Value
- string
By default this is an empty string.
Remarks
This is mostly used to help distinguish between different models of the same type.
NodesSource
Gets or sets the collection of node data items for the model.
IEnumerable NodesSource { get; set; }
Property Value
- IEnumerable
Initially this value is null. It must be set to a non-null, non-empty value for the model to have any "data".
SkipsUndoManager
Gets or sets a flag that controls whether the model notifies any UndoManager that a change has occurred.
bool SkipsUndoManager { get; set; }
Property Value
- bool
This is normally false. You may want to temporarily set this to true in order to avoid recording temporary changes to the model.
UndoManager
Gets or sets the UndoManager for this model.
UndoManager UndoManager { get; set; }
Property Value
- UndoManager
When this value is null, there is no UndoManager, and thus no support for undo/redo.
Methods
AddCollectionCopy(IDataCollection, ICopyDictionary)
Copy existing data and add to this model.
ICopyDictionary AddCollectionCopy(IDataCollection coll, ICopyDictionary env)
Parameters
coll
IDataCollectionthe collection of data to be copied
env
ICopyDictionarythe ICopyDictionary used to keep track of copied objects; if null, the method will call CreateCopyDictionary(), use it, and return it
Returns
- ICopyDictionary
the updated copy dictionary
Remarks
The primary purpose of this method is to perform a two-pass copy of a part of a diagram, and add the resulting data to this model.
Of course you can add node data without copying them by calling AddNode(object) or by just adding them directly to the NodesSource.
Note that this method is universal, because it can only assume the collections are of type IDataCollection and ICopyDictionary. The corresponding methods in the generic model classes operate on and return a specific collection type.
AddLink(object, object, object, object)
Add a link between one node/port and another node/port.
object AddLink(object fromdata, object fromparam, object todata, object toparam)
Parameters
fromdata
objecta node key identifying the node data from which the link comes
fromparam
objectan optional value identifying which port on the "from" node the link is connected to
todata
objecta node key identify the node data to which the link goes
toparam
objectan optional value identifying which port on the "to" node the link is connected to
Returns
Remarks
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
AddNode(object)
Add a node data to NodesSource.
void AddNode(object nodedata)
Parameters
nodedata
object
Remarks
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
AddNodeCopy(object)
Add a copy of a node data to this model.
object AddNodeCopy(object nodedata)
Parameters
nodedata
object
Returns
- object
the copied node data
Remarks
This is a convenience method that just calls AddCollectionCopy(IDataCollection, ICopyDictionary).
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on and return a specific node data type.
ChangeModel(ModelChangedEventArgs, bool)
This is called during an Undo or a Redo to actually make state changes to this model or to this model's data.
void ChangeModel(ModelChangedEventArgs e, bool undo)
Parameters
e
ModelChangedEventArgsan edit describing the change to be performed
undo
booltrue if undoing; false if redoing
ClearUnresolvedReferences()
Forget all unresolved delayed or forward references.
void ClearUnresolvedReferences()
Remarks
The model may learn about node data in any order, so references to nodes may be unresolvable until later, perhaps never. Call this method to clear the internal table that keeps track of node keys that are not defined by the presence of corresponding node data.
CommitTransaction(string)
Call the UndoManager's CommitTransaction method.
bool CommitTransaction(string tname)
Parameters
tname
stringa String describing the transaction
Returns
CreateCopyDictionary()
Create an ICopyDictionary initialized for this model.
ICopyDictionary CreateCopyDictionary()
Returns
- ICopyDictionary
Normally this will be an empty dictionary.
CreateDataCollection()
Create an empty IDataCollection for this model.
IDataCollection CreateDataCollection()
Returns
CreateInitializedCopy(IDataCollection)
Create a copy of this model initialized with different data.
IDiagramModel CreateInitializedCopy(IDataCollection init)
Parameters
init
IDataCollectionthis may be null, meaning no initial data
Returns
- IDiagramModel
a model of the same type as
this
Remarks
Most of the properties of the returned model should have the same value as this model, but the data depends on the argument IDataCollection.
DoNodeAdded(object)
This should be called when a node data object is added to the NodesSource collection.
void DoNodeAdded(object nodedata)
Parameters
nodedata
object
Remarks
This is used for model update, when the model data has changed and the model itself needs to be updated to reflect those changes. Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
If the NodesSource collection implements INotifyCollectionChanged
,
the model will automatically call this method.
Otherwise, you need to do so immediately after the NodesSource has been augmented.
DoNodeKeyChanged(object)
This should be called when a node data's key value may have changed.
void DoNodeKeyChanged(object nodedata)
Parameters
nodedata
object
Remarks
This is used for model update, when the model data has changed and the model itself needs to be updated to reflect those changes. Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
If a node data object implements INotifyPropertyChanged
and if the key is a simple property on the data that the model recognizes,
the model will automatically call this method.
Otherwise, you need to do so immediately after the value of node's key has changed.
DoNodeRemoved(object)
This should be called when a node data object is removed from the NodesSource collection.
void DoNodeRemoved(object nodedata)
Parameters
nodedata
object
Remarks
This is used for model update, when the model data has changed and the model itself needs to be updated to reflect those changes. Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
If the NodesSource collection implements INotifyCollectionChanged
,
the model will automatically call this method.
Otherwise, you need to do so immediately after the NodesSource has been diminished.
FindNodeByKey(object)
Given a key, find the node data with that key.
object FindNodeByKey(object key)
Parameters
key
objecta value of null for this argument will result in the default value for the node data Type
Returns
- object
a node data with that key, if it is present in the model; the value will be the default for the type if no such node data is known to be in this model
Remarks
This is used for model navigation.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
GetCategoryForNode(object)
To help distinguish between different kinds of nodes, each node has a "category" that is just a string.
string GetCategoryForNode(object nodedata)
Parameters
nodedata
object
Returns
- string
the default category is the empty string
GetConnectedNodesForNode(object)
Return a sequence of node data that are directly connected to a given node, in either direction.
IEnumerable<object> GetConnectedNodesForNode(object nodedata)
Parameters
nodedata
object
Returns
Remarks
This is used for model navigation and graph traversal.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
GetFromNodesForNode(object)
Return a sequence of node data that are directly connected by links going into a given node.
IEnumerable<object> GetFromNodesForNode(object nodedata)
Parameters
nodedata
object
Returns
Remarks
This is used for model navigation and graph traversal.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
GetNodeType()
Return the Type of the node data.
Type GetNodeType()
Returns
Remarks
This is useful for data transfer.
GetToNodesForNode(object)
Return a sequence of node data that are directly connected by links coming out from a given node.
IEnumerable<object> GetToNodesForNode(object nodedata)
Parameters
nodedata
object
Returns
Remarks
This is used for model navigation and graph traversal.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
IsLinkValid(object, object, object, object)
This predicate is true if adding a link between two nodes/ports would result in a valid graph.
bool IsLinkValid(object fromdata, object fromparam, object todata, object toparam)
Parameters
fromdata
objecta node key identifying the node data from which the link comes
fromparam
objectan optional value identifying which port on the "from" node the link is connected to
todata
objecta node key identify the node data to which the link goes
toparam
objectan optional value identifying which port on the "to" node the link is connected to
Returns
IsLinked(object, object, object, object)
This predicate is true if there is a link from one node data/port to another one.
bool IsLinked(object fromdata, object fromparam, object todata, object toparam)
Parameters
fromdata
objecta node key identifying the node data from which the link comes
fromparam
objectan optional value identifying which port on the "from" node the link is connected to
todata
objecta node key identify the node data to which the link goes
toparam
objectan optional value identifying which port on the "to" node the link is connected to
Returns
- bool
true if there are any links
Remarks
This is used for model navigation and graph traversal.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
IsNodeData(object)
This predicate is true if the argument is a node data in this model.
bool IsNodeData(object nodedata)
Parameters
nodedata
objectthe object to be checked to see if it is a known node data in this model
Returns
- bool
true if the
nodedata
is in the NodesSource
Remarks
This is used for model navigation.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
IsNodeType(object)
This predicate is true when the argument is an instance of the node data Type.
bool IsNodeType(object nodedata)
Parameters
nodedata
objectthe arbitrary object to be checked for compatibility to be a node data
Returns
- bool
true if the
nodedata
can be cast to the the node data Type; false otherwise
RaiseChanged(ModelChangedEventArgs)
Raise a Changed event, given a ModelChangedEventArgs.
void RaiseChanged(ModelChangedEventArgs e)
Parameters
e
ModelChangedEventArgsa ModelChangedEventArgs that describes what changed and how
RemoveLink(object, object, object, object)
Remove all links connecting the two nodes/ports in the one direction.
void RemoveLink(object fromdata, object fromparam, object todata, object toparam)
Parameters
fromdata
objecta node key identifying the node data from which the link comes
fromparam
objectan optional value identifying which port on the "from" node the link is connected to
todata
objecta node key identify the node data to which the link goes
toparam
objectan optional value identifying which port on the "to" node the link is connected to
Remarks
This method can have potential side-effects, such as removing nodes that are labels on the link.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
RemoveNode(object)
Remove node data from NodesSource.
void RemoveNode(object nodedata)
Parameters
nodedata
object
Remarks
This method can have potential side-effects, such as removing links that are connected to the nodedata
.
Note that this method is universal, because it can only assume the node data is of type object. The corresponding methods in the generic model classes operate on a specific node data type.
RollbackTransaction()
Call the UndoManager's RollbackTransaction method.
bool RollbackTransaction()
Returns
StartTransaction(string)
Call the UndoManager's StartTransaction method.
bool StartTransaction(string tname)
Parameters
tname
stringa String describing the transaction
Returns
- bool
the value of the call to StartTransaction
Events
Changed
The Changed event is raised whenever the model is modified.
event EventHandler<ModelChangedEventArgs> Changed
Event Type
- See Also
-
StockSharp.Xaml.Diagram.GXDiagram.Model.ModelChange