Link creation doubt

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

    Posted 24 Jan 2013 Link to this post

    When you start dragging from a connector, a Link object is immediately created and added to the diagram. I would argue that the link is added too early since it's not live until you release the mouse, but that aside! When you do release the mouse on another connector, we need to update our internal representation of the flow diagram. Hence, it makes sense to connect source and target since that is what happened. Now...

    This function seems to be what we are looking for. However, target is always null (since the link is created too early :P).
    public override ILink CreateLink(object source, object target)

    At some point we need to know which two connectors were connected. Where do we find such an event/method override? Our best bet so far is overriding the ConnectionManipulationCompleted event, but it seems we cannot determine which two connectors were actually linked:

    private void diagram_ConnectionManipulationCompleted(object sender, ManipulationRoutedEventArgs e)
    {
        if (e.ManipulationStatus == ManipulationStatus.Attaching)
        {
            var startShape = e.Connection.Source as MyShape;
            var endShape = e.Connector.Shape as MyShape;

            // WHICH connectors where connected?

             ...
        }
    }

    If we drag from Node1.Left to Node2.Right we ought to get this piece of information. How? (Note that we have our custom connectors.

  2. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 29 Jan 2013 Link to this post

    Hi Kristoffer,

    In the event handler of the RadDiagram.ConnectionManipulationCompleted event, you can get the target connector through the e.Connector property. The source connector you can access through the e.Connection.SourceConnectorResult:
    private void diagram_ConnectionManipulationCompleted(object sender, Telerik.Windows.Controls.Diagrams.ManipulationRoutedEventArgs e)
    {
        if (e.ManipulationStatus == ManipulationStatus.Attaching)
        {
            var sourceConnector = e.Connection.SourceConnectorResult;
            var targetConnector = e.Connector;
        }
    }

    You can also bind the RadDiagramConnection SourceConnectorPosition and TargetConnectorPosition properties to business properties and track the values of the business properties in your ViewModels to get the names of the source and target connectors of a connection.

    I prepared a sample solution demonstrating both approaches so that you can decide which one will best suit your needs.

    Regards,
    Tina Stancheva
    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 29 Jan 2013 Link to this post

    That helped. Thank you very much!

    (I could not open the Solution as I'm using VS 2010 here.)
  5. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 29 Jan 2013 Link to this post

    One more question. In your sample you have this code:

    public CustomLink()
         : base()
    {
         SourcePosition = "Auto";
         TargetPosition = "Auto";
    }

    In my application, I have custom connectors. Hence, no Auto connector. So, when the CustomLink is created I cannot know which was the source connector.

    public override ILink CreateLink(object source, object target)
    {
          MyNode node = source as MyNode;
          // How can I know which connector was the starting point?
    }

    If I don't set the connector name, I get an exception that a connector with the name '' (empty string) cannot be found. Similar to the problem described here:
    http://www.telerik.com/community/forums/wpf/diagram/treelayout-does-not-work-for-custom-connectors.aspx
  6. Kristoffer
    Kristoffer avatar
    158 posts
    Member since:
    Dec 2012

    Posted 29 Jan 2013 Link to this post

    To keep my data (viewmodel) synchronized with the GraphSource, I have overriden all methods in my ObservableGraphSourceBase<FilterNode, Link> derived class. Ideally, I would use TwoWay-binding for the GraphSource and use a converter. Anyway, now I have these overridden methods...

    E.g.
    public override void AddLink(Link link)
    {
        // Synchronization logic needed here! But link.target is null!!
       
        base.AddLink(link);
    }

    That function is the root of all evil. It is called when a connection is being dragged - before it is attached. Hence, there is no way for me to successfully keep my underlying data synchronized with the view (the GraphSource). There should be another method called "UpdateLink" which is called when the connection is attached. Or maybe you should not call "AddLink" in the first place...

    I did manage to work around this limitation, but the resulting code is horrible (a disaster in terms of MVVM):

    private void diagram_ConnectionManipulationCompleted(object sender, ManipulationRoutedEventArgs e)
    {
        if (e.ManipulationStatus == ManipulationStatus.Attaching)
        {
            var source = e.Connection.Source as MyChartShape;
            var target = e.Connector.Shape as MyChartShape;
           
            var sourceConnector = e.Connection.SourceConnectorResult;
            var targetConnector = e.Connector;

            var viewModel = diagram.DataContext as DiagramViewModel; // URK
            var connection = e.Connection as MyChartConnection;
           
            var outPin = source.MyObject.GetConnector(sourceConnector.Name);
            var inPin = target.MyObject.GetConnector(targetConnector.Name);

            viewModel.Graph.Connect(outPin, inPin);
        
            // connection.SourceConnectorPosition = sourceConnector.Name;
            // connection.TargetConnectorPosition = targetConnector.Name;
           
            this.InvokeDispatchedLayout(false);
        }
    }

    I also tried binding SourceConnectorPosition as you pointed out, but it doesn't work.

  7. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 31 Jan 2013 Link to this post

    Hi Kristoffer,

    In my solution the position properties I set in the CustomLink constructor are simply initial values - basically values by default. As soon as you drag or connect a connection, both values are getting updated.

    However, you need to have in mind that when you create a connection in an MVVM diagramming solution, the visual element - RadDiagramConnection, is created only after the GraphSource AddLink() method successfully adds the business link in the GrapghSource collection. This is the main purpose of the AddLink method - to allow you to prepare the business representation of the connection and manually add it in the GraphSource collection. Then, once it's added, the RadDiagram creates the RadDiagramConnection and sets its SourceConnectorPosition/SourceConnectorResult properties accordingly. This is why the source connector properties (like the SourceConnectorPoisiton) aren't yet generated in the AddLink/CreateLink() methods of the ObservableGraphSourceBase implementation and you can't access their real values.

    Also, unless you connect the end of the connection to another shape, the RadDiagramConnection won't know that it has a TargetConnector and the TargetConnector-related properties will be also unset.

    And the "connector with the name '' (empty string) cannot be found" exception is thrown when you try to bind the SourceConnectorPosition and TargetConnectorPosition to business values which are an empty string - once the RadDiagramConnection starts initializing, the binding tries to set the connectors positions but can't find any connectors with that name. But if you define default values for the business properties, the control will update them accordingly as soon as all related visual elements are properly generated. This is why I suggested that you use the PropertyChanged callback or the setter of the ConnectorPosition-related business properties to track their value.

    As for your last post, unfortunately I'm not sure I understand your requirements correctly. Specifically I don't know what you mean by "keep my data (viewmodel) synchronized with the GraphSource" and "I would use TwoWay-binding for the GraphSource and use a converter". Can you please elaborate a bit more on that and send us a sample solution demonstrating your scenario? This way we'll be able to better understand the context of your issues and advice you how to implement your requirements.

    Kind regards,
    Tina Stancheva
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

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

    Posted 10 Apr 2013 Link to this post

    I'm still trying to fix this issue. There is a need for the UpdateLink method suggested below!

    Let's say I successfully create a connection between node A and node B. Then I press Delete and the connection is about to be removed. When this occurs, I want to update my underlying (primitive) data structure to reflect this change. Hence, I override RemoveLink:

    public override bool RemoveLink(Link link)
    {
        if (base.RemoveLink(link))
        {
             // Update data structure
             // But...
             // ... all members of link are null...
        }
    }

    I need the Link instances to update themselves on connection completion.

    The only possible solution I can think of at the moment is to somehow find the Link in the ConnectionManipulationCompleted event. Suggestions?
  9. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 15 Apr 2013 Link to this post

    Hi Kristoffer,

    I'm not sure why the RemoveLink() approach doesn't work for you and this is why I can't suggest if there is a better approach. On our side in a sample MVVM application with a GraphSource deriving from ObservableGraphSourceBase<TNode,TLink>, I can't reproduce the issue. Do you think you can send over a sample solution where we can examine why the link object members are all null?

    Thank you in advance.

    Kind regards,
    Tina Stancheva
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  10. Mike
    Mike avatar
    13 posts
    Member since:
    Dec 2010

    Posted 25 Jul 2013 Link to this post

    FYI, I was having the exact same issue with AddLink having the Target property always null.  I almost posted, instead verified I had the latest distribution, upgraded, and finally.....whew, I'm not crazy.....Target is populated.
  11. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 30 Jul 2013 Link to this post

    Hi Mike,

    With the Q2 2013 SP release we introduced changes within the RadDiagramConnection creation and the GraphSourceBase methods so that now if you override the AddLink() method you can access both the source and target nodes of a link, if such exist.

    I hope these changes will facilitate your efforts when creating MVVM diagramming solutions. And please don't hesitate to write back with any feedback on the matter.

    Regards,
    Tina Stancheva
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WPF.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top
UI for WPF is Visual Studio 2017 Ready