How to dynamically change node appearance?

Hi,

I’m trying to dynamically (programmatically) change the appearance of a node, and i don’t understand how i can do this.

i would like to drag a node from the palette to the diagram and change its appearance once it is dropped on the diagram. The node in the palette have a simple appearance and i would like the dropped node to have a more complex one.

At the moment, i have tried to define 2 dataTemplates in my NodeTemplateDictionnary, which corresponds to 2 categories, and change the node category during the OnNodeAdded() method of my custom PartManager. But that do not force the node to redraw with its new appearance. i presume only change the category isn’t sufficient.

I also would like to be able change the appearance on other types of interaction between the UI and the user, such as a click on a button or almost any kind of event.

Is there a way to do that ? And How ?

Thanks for your help.

If you always want one appearance in one diagram (e.g. the Palette) and another appearance in another diagram (e.g. the main Diagram), then just use different DataTemplates. In this case you’re not actually replacing the template for a node (or link) dynamically.

If you are using version 1.1, it supports dynamically changing the Category for a node data (or link data). Basically the PartManager detects the …Model.Changed event announcing ModelChange.NodeCategoryChanged, and just removes from the Diagram the Node for a particular node data and then creates a new Node using a different DataTemplate from the DataTemplateDictionary.

If you are using version 1.0, you can do this work yourself. In 1.0 the models do not keep track of changes to the Category for any data, so naturally the PartManager doesn’t know about changing categories. You’ll need to call PartManager.RemoveNodeForData and then AddNodeForData.

Oh, and regarding changing the appearance when the user does some mouse events in a node, that doesn’t really involve GoXam at all. Everything you’ve learned about Silverlight or WPF programming still applies inside a node.

Unfortunately, i’m using version 1.0.

If i need to remove the node and create a new copy of it, with a different dataTemplate means that there is no way to change the appearance of a node on the fly (And get its appearance from a dataTemplate if possible) ?

I not really interrested in removing and recreating a node because, in my current implementation, my nodes are binded to databases record and removing a node imply, remove a record from database.

I have started to learn Silverlight with this GoXam projet, so i’m a newbie in Silverlight programming.

No, I didn’t mean to imply removing the node data from the model. That would cause side effects that you wouldn’t want.

I just meant removing the Node from the Diagram and then creating it again, from the same unmodified node data, using the PartManager.

All right, so this "node switch"will not affect the model, only what we saw in the diagram.

In fact, i need to replace the Node object with a new one using the same Node.Data object, and this using the PartManager.RemoveNodeForData() and PartManager.AddNodeForData() methods. Is that right ?

End of the day in France, so i have to go. I will try this tomorrow morning and let you know…

I tried something this morning but I can’t figure out where/when do I need to change the category attribute.
Do I need to change the category in the nodeData object or in the Node object ?
Which one is used to redraw the node ? Where does the category attribute is read from when the new node is drawn ?

I tried to do the “node switch” in the OnNodeAdded() method of my custom PartManager class, like so :

Protected Overrides Sub OnNodeAdded(ByVal node As Northwoods.GoXam.Node)
        MyBase.OnNodeAdded(node)

        Try
            If CType(node.Data, NodeGoXam).Category = "Standard" Then
                Me.RemoveNodeForData(node.Data, ApplicationSharedData.Model)
                CType(node.Data, NodeGoXam).Category = "StandardCas1"
                Me.AddNodeForData(node.Data, ApplicationSharedData.Model)
            End If

        Catch ex As Exception

        End Try
    End Sub

I would like the new node to be drawn with the appearance defined by my DataTemplate corresponding to category “StandardCas1”.

The more i dig, the more i start to think that Category is not directly linked to which dataTemplate is used to render the node.

Can you tell me more on that topic ?

I don’t think you want to modify your data nor do you want to add or remove nodes in an override of PartManager.OnNodeAdded (or any of the other similar overridable methods). Perhaps we should have made that clearer in the documentation.

Basically what your code is doing is changing the Category of every “Standard” node data that you have added to your model to be “StandardCas1”. That means you can’t have any “Standard” category nodes at all in your diagram.

Doing:

  myDiagram.PartManager.RemoveNodeForData(data, ApplicationSharedData.Model)
  data.Category = "StandardCas1"
  myDiagram.PartManager.AddNodeForData(data, ApplicationSharedData.Model)

is the right thing to do when you want to change the appearance of some data. Just don’t do it in an override of any PartManager method.

Well i also tried this, but the only result I got is that the node disappears from the diagram (Because of RemoveNodeForData). When the next Layout happens, the node reappears in the top left corner of the diagram (Because of the AddNodeForData), but the appearance is still the same. So, the node seems to be redrawn using the same dataTemplate.

Private Sub Affectation_MouseLeftButtonDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)

        Dim nodeData As NodeGoXam = TryCast(Part.FindAncestor(Of Node)(TryCast(sender, UIElement)).Data, NodeGoXam)

        myDiagram.PartManager.RemoveNodeForData(nodeData, ApplicationSharedData.Model)
        nodeData.Category = "Standard"
        myDiagram.PartManager.AddNodeForData(nodeData, ApplicationSharedData.Model)
        myDiagram.LayoutDiagram()

    End Sub

In this case, i tried to change a “StandardCas1” category node appearance to a “Standard” one.

I’m obviously missing something…

Which method decide which dataTemplate will be use to render a node ?

Actually, I’m the one who missed something in getting this to work in version 1.0.

I modified the FlowChart sample by adding a Button and this event handler:

private void Button_Click(object sender, RoutedEventArgs e) { if (myDiagram.SelectedNode != null) { MyNodeData data = myDiagram.SelectedNode.Data as MyNodeData; if (data != null) { myDiagram.StartTransaction("change category"); myDiagram.PartManager.RemoveNodeForData(data, myDiagram.Model); switch (data.Category) { case "Start": data.Category = "Standard"; break; case "Standard": data.Category = "End"; break; case "End": data.Category = "Start"; break; } myDiagram.PartManager.AddNodeForData(data, myDiagram.Model); myDiagram.CommitTransaction("change category"); } } }
This is exactly as I said before.

What I forgot is that the v1.0 models assume that the category never changes. In order for the above data change to have any effect, override the PartManager.FindCategoryForNode method:

public class MyPartManager : PartManager { protected override string FindCategoryForNode(object nodedata, IDiagramModel model, bool isgroup, bool islinklabel) { MyNodeData data = nodedata as MyNodeData; if (data != null) return data.Category; return base.FindCategoryForNode(nodedata, model, isgroup, islinklabel); } }
And install the new PartManager by setting:
myDiagram.PartManager = new MyPartManager();

All right, it works great now ! Thanks you for your help, again !