Northwoods.GoWPF 2.2.4 Assembly
IDiagramModel Interface
Members 

All diagram models implement this interface or an interface that inherits from this interface.
Syntax
Public Interface IDiagramModel 
public interface IDiagramModel 
Remarks

This is reponsible for defining relationships between nodes, involving links and grouping. It does not know about any FrameworkElements (including Northwoods.GoXam.Diagram or Northwoods.GoXam.DiagramPanel or Northwoods.GoXam.Part). It just knows about .NET CLR objects as data of type System.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 Northwoods.GoXam.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, DoNodeRemoved, and DoNodeKeyChanged. More specific kinds of models have additional methods, such as: ITreeModel.DoParentNodeChanged, DoToNodeKeyRemoved, ILinksModel.DoLinkAdded, IGroupsModel.DoMemberNodeKeysChanged, and ISubGraphModel.DoGroupNodeChanged. 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 and DoNodeRemoved 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 TreeModelNodeData<NodeKey>.

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 method is called right after changing a node's key.

The FindNodeByKey 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 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, GetFromNodesForNode, GetToNodesForNode, GetConnectedNodesForNode. Particular kinds of models have additional methods for traversing graphs, such as: ITreeModel.GetChildrenForNode, ILinksModel.GetLinksBetweenNodes, ILinksModel.GetToNodeForLink, ILinksModel.GetLabelNodeForLink, IGroupsModel.GetMemberNodesForGroup, and ISubGraphModel.GetGroupForNode. 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 and RemoveNode. For links, there are AddLink and RemoveLink. Furthermore, particular kinds of models have additional methods for changing relationships, such as: ITreeModel.AddChildNodeKey, AddFromNodeKey, ILinksModel.SetLinkLabel, IGroupsModel.RemoveMemberNodeKey, and ISubGraphModel.SetGroupNode. 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. 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 method.

Depending on the application, not all relationships should be possible. Models provide support for link relationships with the IsLinkValid method. There are more specific model predicates for IsRelinkValid: ILinksModel.IsRelinkValid, IConnectedModel.IsRelinkValid, and ITreeModel.IsRelinkValid. IGroupsModel.IsMemberValid 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. 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 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 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 and CommitTransaction. If after a StartTransaction 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.

Requirements
See Also

Reference

IDiagramModel Members
Northwoods.GoXam.Model Namespace
ITreeModel Interface
IConnectedModel Interface
ILinksModel Interface
IGroupsModel Interface
DiagramModel Class
GraphLinksModel<NodeType,NodeKey,PortKey,LinkType> Class
GraphModel<NodeType,NodeKey> Class
TreeModel<NodeType,NodeKey> Class

 

 


© Northwoods Software 2017. All Rights Reserved.

Send Feedback