This is a migrated thread and some comments may be shown as answers.

GraphSource does not implement INotifyCollectionChanged

13 Answers 157 Views
Diagram
This is a migrated thread and some comments may be shown as answers.
Kristoffer
Top achievements
Rank 1
Kristoffer asked on 16 Jan 2013, 01:57 PM
Seems like a bug. Now I have to re-assign the GraphSource instance in order to see changes in the view. Adding/removing items has no effect.

13 Answers, 1 is accepted

Sort by
0
Petar Mladenov
Telerik team
answered on 16 Jan 2013, 04:42 PM
Hi Kristoffer,

 What kind of GraphSource do you use ? Actually our ObservableGraphSourceBase supports two-way scenarios out of the box. Please check out this help article (section "Two-Way MVVM") and let us know if it helped you or not.

All the best,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Kristoffer
Top achievements
Rank 1
answered on 28 Jan 2013, 09:03 AM
public class GraphSource : ObservableGraphSourceBase<MyNode, MyLink>

When the functions AddNode, AddLink or any of the other graph source modifying functions are called - the GraphSourceChanged event is not fired. Do I need to explicitly fire it in my GraphSource class?

If I re-assign the GraphSource object, the event is indeed fired, but that doesn't help in this scenario...
0
Kristoffer
Top achievements
Rank 1
answered on 29 Jan 2013, 02:29 PM
If I remove nodes, my GraphSource.Items collection is changed. I would expect the GraphSourceChanged to trigger, but it does not. Why?

This behavior can be seen in your own sample:
http://www.telerik.com/ClientsFiles/21906545-719f-406c-9e2e-b1b7d00140fa_WpfApplication1.zip
0
Petar Mladenov
Telerik team
answered on 30 Jan 2013, 05:33 PM
Hello Kristoffer,

 This event is designed to fire only when the GraphSource is set or reset. Imagine a Diagram with 5000 shapes. Do you really need an event firing internally on every on of 5000 NodeViewModels added internally. This will boost performance. However, you can be notified when a link is added , for example like so:

(this.diagram.GraphSource as ObservableGraphSourceBase<Node, Link>).InternalItems.CollectionChanged += InternalItems_CollectionChanged;
        }
 
        void InternalItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            throw new NotImplementedException();
        }
(Supposing your GraphSource is from type ObservableGraphSourceBase<Node, Link>).
Could you please elaborate more on your scenario, what do you need to do when a link / node is added in the graph source. Probably there is a simpler way to achieve what you need, we would be glad to assist you further.

Greetings,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Kristoffer
Top achievements
Rank 1
answered on 31 Jan 2013, 08:26 AM
Hi,

What we want to accomplish is to keep the GraphSource synchronized with our underlying (executable) data structure - at all times. Hence, when we add nodes we must add a node on our underlying data structure - and vice versa. We have managed to get this working using a number of painful tricks:

1) When our data structure D is updated, we rebuild the GraphSource from scratch and assign it. No performance loss here!
2) When the user modifies the graph using the UI, we keep it in sync with D by overriding the following methods: AddNode(), AddLink(), Clear(), RemoveItem(), RemoveLink()
3) Adding links/connections from UI is a total mess. Since AddLink() is called with no target set, we have to fetch the ConnectionManipulationCompleted event and explicitly modify D from there. Of course, D lives in our viewmodel so we have to dig a bit to get hold of it.
4) To avoid "visual tree" exceptions, we have to modify the UI first, then the underlying data D. I would rather do it the other way around since D should be valid at all times! It could happen that D does not accept a connection and we would then need to further mess up our logic in the ConnectionManipulationCompleted event.

To clarify #4. Today we have the code below. We want to swap the order of the function calls!

public override void AddNode(MyNode node)
{
    base.AddNode(node);

    Graph.AddMyNode(node.Data); // Might fail!
}


As you can imagine, all these steps effectively move us away from a clean MVVM design. Either we have too little knowledge to implement this the right way, or your diagram component lacks the ability to nicely accomplish what we want. You tell me :)

Possible improvements
Ideally, we would want a TwoWay-binding between GraphSource and D with a nice converter. Otherwise, it would be nice if AddLink() had an equivalent method that was called when the link has indeed been attached so that we can skip the nasty #3 above. #4 is also of interest. Maybe you should pause the updating of the UI while your framework is calling the mentioned functions?
0
Accepted
Petar Mladenov
Telerik team
answered on 05 Feb 2013, 07:50 AM
Hi Kristoffer,

We understand your frustration. Indeed, point 3 shows weakness in the MVVM mechanism in our Diagramming Framework. That's why we logged as feature request in our PITS describing this situation and how it should be handled. We also updated your telerik account points as a thanks for your cooperation.
As for point 4, could you please elaborate more on it, is it possible for you to illustrate it better with example scenario? How do you achieve visual tree exceptions? 

All the best,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Kristoffer
Top achievements
Rank 1
answered on 05 Feb 2013, 09:27 AM
Thanks. Fixing #3 would make life easier for us. Any chance for this fix in the next couple of weeks?

As for #4, I believe it is caused by some cyclic binding from our underlying data. It could very well be a problem in our code (indirectly caused by #3). I will investigate it, and if I suspect an issue in your framework, I'll submit a sample project.
0
Petar Mladenov
Telerik team
answered on 06 Feb 2013, 09:53 AM
Hello Kristoffer,

The mentioned feature request is very complicated and requires huge re-factoring of our code. That's why we cannot promise an estimated time frame when it will be implemented.  On the other hand, there are situations in which our clients may want to have the AddLink() invoked on the start of the connection creation. This is how our Drawing Tools (and the Text tool which will be released in Q1) work actually - the shape which you draw is created on the start of the drawing process. Same is currently true for our Connections and changing this behavior will be a serious breaking change in the framework. That is why we logged it a feature request (not a bug) and we will consider implementing it if it gathers enough votes.

We know that pure MVVM is not a achievable in your scenario but this is typical for large Frameworks - when pure MVVM is not easy to achieve, there are events ready to help. However, I am not sure whether we suggested you to use the Source and Target property setters in your MVVM solutions. The setter of the Target in the ViewModel will fire when you attach a connection with a mouse in a 2-way mvvm scenario. Have you considered using this instead of ConnectionManipulationCompleted event if possible ?

All the best,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Kristoffer
Top achievements
Rank 1
answered on 06 Feb 2013, 10:07 AM
Thanks. We will investigate if the suggested binding would solve our problems.

Regarding refactoring. Don't change AddLink. Just add a second function, UpdateLink, which is called when the link is attached. That cannot break your code.
0
Petar Mladenov
Telerik team
answered on 07 Feb 2013, 06:21 AM
Hello Kristoffer,

 Thank you for your feedback. We will definitely consider such option and we will add it in the description of the feature request.

All the best,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Petar Mladenov
Telerik team
answered on 04 Mar 2013, 04:57 PM
Hello Kristoffer,

We wanted to update you on this topic. As we discussed previously, you needed to know in the ViewModel when a Connection Target is being updated. Attached you can find  2 samples demonstrating two different approaches for this requirement:
1) The first one uses LinkViewModel and its PropertyChanged event:

public class Link : LinkViewModelBase<Node>
    {
        public Link ()
        {
            this.PropertyChanged += Link_PropertyChanged;
        }
 
        void Link_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Target")
            {
                MessageBox.Show("Target Attached");
            }
        }
    }
2) The second uses ILink where you can use the Setter of the target property as we suggested you.

We hope these solutions will help you proceed further. However, we will be working on improving our GraphSouce classes as the mentioned PITS feature request describes.

Greetings,
Petar Mladenov
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

0
Kristoffer
Top achievements
Rank 1
answered on 10 Apr 2013, 12:27 PM
Link_PropertyChanged is a good start. Thanks.

But, inside this event handler, how would you know which connectors were actually connected? Knowing which two nodes were connected does not suffice when there are multiple connectors present!
0
Tina Stancheva
Telerik team
answered on 15 Apr 2013, 02:40 PM
Hello Kristoffer,

Unfortunately you won't be able to access the connectors to which the link is being connected in the PropertyChanged handler. And for now it might be best to keep your ViewModel update logic in the ConnectionManipulation-related events.

And for the next release, we're planning to slightly change the AddLink()/CreateLink() methods implementation. Basically, we'll leave the CreateLink() implementation as is and the method will be invoked as soon as a new link is about to be created. But the AddLink() method will be invoked only after the mouse is released and the connection is connected to a shape or just left floating on the diagramming surface. This will allow you to get a reference of both the Source and the Target shapes of a connection in your ViewModel and if you bind the RadDiagramConnection SourceConnectorPosition and TargetConnectorPosition properties, they should also be properly updated so that you can track the connector to which a connection is attached in the AddLink() method.

But for the time-being it might be best to keep your logic in the ConenctionManipulationStarted and ConnectionManipulationCompleted event handler. I described the logic of these events in this forum thread.

Regards,
Tina Stancheva
the Telerik team

Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

Tags
Diagram
Asked by
Kristoffer
Top achievements
Rank 1
Answers by
Petar Mladenov
Telerik team
Kristoffer
Top achievements
Rank 1
Tina Stancheva
Telerik team
Share this question
or