Creating Groups

I have a question regarding Group creation.
When node source use an observable collection, and when I call method AddNodeForData then Group is created as expected. But when it’s a normal collection, I have to use method MakeNodeForData to be able to create a group. Unfortunately lots of properties are not initialized (for example Bound). Do I miss an init call somewhere?

Thanks

Are you calling PartManager.MakeNodeForData? Notice that that method is protected – it is just used internally to allow for customization of construction and initialization of the Node that the PartManager creates for some model data.

If you want to add a node data object to the model, just call IDiagramModel.AddNode or IDiagramModel.AddNodeCopy.

When I’m using IDiagramModel.AddNode a node is created not a Group.

Is the data not recognized to be a group?
Check the GraphLinksModel.NodeIsGroupPath property or the result of calling GraphLinksModel.GetIsGroupForNode method.

GraphLinksModel.NodeIsGroupPath return “IsSubGraph”

Yes, Group is not recognized. I get always a Node. As I do not have defined Node template I wonder why I saw at first nothing.
Property IsSubGraph is set in Data Constructor and never changed and have the right value when calling AddNodeForData.
Strange that it’s works with an ObservableCollection

Ah, you already answered my question. Hmmm, I’ll look into this some more.

If the NodesSource property value implements INotifyCollectionChanged, the model adds an CollectionChanged listener which calls GraphLinksModel.DoNodeAdded. So when you add data to the collection, the model is notified.

If the NodesSource property value does not implement INotifyCollectionChanged, then when you call AddNode, which calls InsertNode, which actually adds the data to the collection, and (because the collection does not implement INotifyCollectionChanged) it explicitly calls DoNodeAdded.

So either way DoNodeAdded is called, and that common code is what actually calls PartManager.AddNodeForData for each Diagram. That method finds the data object’s Category and whether it IsGroup. It then calls PartManager.FindTemplateForNode, which finds the appropriate template.

I suppose you could break at FindTemplateForNode to see what it returns.

OK, I’ve never used GroupTemplateDictionary as I’ve only have 1 Group template.
For testing, I’ve added a value String MyCategory in GraphLinksModelNodeData object.

MyCategory = "GraphGroupTemplate";

I’ve added groupTemplate inside a DataTemplateDictionary:

<gowpf:DataTemplateDictionary x:Key="Group">
    <DataTemplate x:Key="GraphGroupTemplate" DataType="{x:Type viewModel:GraphNodeViewModel}">
. . .

Set Category path

model.NodeCategoryPath = "MyCategory";

And finally I’ve set the Group Template to the diagram

GroupTemplateDictionary="{StaticResource Group}"

Then to verify values from part manager Ive made following test:

public void Test(object data)
{
   var cat = FindCategoryForNode(data, Diagram.Model, true, true);
   var c = FindTemplateForNode(data, Diagram.Model, true, true, "GraphGroupTemplate");
}


Category is still not recognized.
FindTemplateForNode(data, Diagram.Model, true, true, “GraphGroupTemplate”) return an DataTemplate object

Do I really have to use a dictionary if I only have one template for group.?

AddNodeForData still return a Node.

No, if there is only one template for Groups, you can just set Diagram.GroupTemplate and you won’t care about category.

How does that data object declare itself to be a Group rather than a regular Node?

In Construtor property IsSubGraph is set to true.

So if you call GraphLinksModel.GetIsGroupForNode on that data object, it returns true, yet the Node that is created isn’t an instance of Group? If so, I cannot explain that.

GraphLinksModel.GetIsGroupForNode return false

with data object:
public class GraphNodeViewModel : GraphLinksModelNodeData
and model
new GraphLinksModel<GraphNodeViewModel, string, string, GraphConnectionViewModel>();

OK, well, that method returning false explains why the Node isn’t also a Group.

But why GetIsGroupForNode is returning false for that object when its IsSubGraph property is true, is very odd to me. You already said that GraphLinksModel.NodeIsGroupPath is “IsSubGraph”, so it isn’t that the model is checking the wrong property to decide whether the data is supposed to be represented by a Group instead of a Node. So I cannot explain that behavior with the information I have. I suppose I would check the value of GraphLinksModel.NodeIsGroupPath again.

It is the case that one cannot change some data to be represented by a Group instead of a Node after the data has been added to the model, nor the other direction, changing a Group back into a Node. That limitation is probably not applicable here, but I thought I should mention it just in case.

GraphLinksModel.NodeIsGroupPath = “IsSubGraph”

Are you still calling PartManager.MakeNodeForData, even though you probably shouldn’t be?

That is the method that actually constructs either a new Node or a new Group, depending on the isgroup argument. It is only called by PartManager.AddNodeForData, as I explained above.

Nope, I do not call MakeNodeForData anymore. I only call AddNodeForData (As it is in Virtualization example), as you told me.

The only difference between working and not working code is the collection declaration.

So what do you use for the source collection? Does it implement INotifyCollectionChanged?

Once it an ObservableCollection and the other it’s a normal Collection.
As I initiate the node creation with PartManager.AddNodeForData I do not see any reason to manage a collection notification.

I just tried a random sample involving groups. I changed the two sources from ObservableCollection to Collection. Everything seems to work well, even after copying a group. The Collection has been modified correctly, as far as I can tell.

Hi Walter,

I’m come back to this purpose. Reading again your comments show me that I’ve never called DoNodeAdded method in the case of a standard list of Node. this may explain why I’ve always had a Node part and not a Group Part in my previously tests.

Here is the process I use to manage groups without observable collection.

1/ When a group is new, I call DoNodeAdded to add it to my Model. Regarding to Virtualization it will or not create a Part in the ViewPort.

2/ When a Group is already in added to my Model, I call Method AddNodeForData to add visible groups in the ViewPort.

Do you agree with this process? At least it works as I expected it.

In my environment it’s possible to insert a group between 2 groups. With an observable collection it wasn’t a problem subgraph was set in group and part was properly linked to it’s parent. But now when I’m inserting a group between 2 other group, the deeper group is not linked to it’s new subgraph, it’s linked to nothing?

Here a comparison between same Part inserted (left) and when part is added (right)

As ContainingSubGraph is only a get property, I can imagine that I miss a call notification to be able to actualized/synchronized the part value when SubgraphKey has been changed.

Could you help me please.