GraphSource does not implement INotifyCollectionChanged

14 posts, 1 answers
  1. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 16 Jan 2013 Link to this post

    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.
  2. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 16 Jan 2013 Link to this post

    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.

  3. UI for WPF is Visual Studio 2017 Ready
  4. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 28 Jan 2013 Link to this post

    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...
  5. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 29 Jan 2013 Link to this post

    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
  6. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 30 Jan 2013 Link to this post

    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.

  7. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 31 Jan 2013 Link to this post

    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?
  8. Answer
    Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 05 Feb 2013 Link to this post

    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.

  9. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 05 Feb 2013 Link to this post

    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.
  10. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 06 Feb 2013 Link to this post

    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.

  11. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 06 Feb 2013 Link to this post

    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.
  12. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 07 Feb 2013 Link to this post

    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.

  13. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 04 Mar 2013 Link to this post

    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.

  14. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 10 Apr 2013 Link to this post

    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!
  15. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 15 Apr 2013 Link to this post

    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.

Back to Top
UI for WPF is Visual Studio 2017 Ready