Strange scrolling behavior

Hi,

we have a problem with scrolling diagrams with big nodes. After adding nodes to the diagram in a transaction, the diagram area trims the nodes at the bottom, and those that are really large in size. Attempting to update DiagramBounds does not work. If, after loading the diagram, we change e.g. the location of any node, the problem is fixed. But some of these diagrams are read only - users cannot make any changes to fix this problem.

All these operations are made in the main thread.

Best regards, and waiting for your help.

Could you please provide more information about how you are adding “nodes to the diagram in a transaction”? Are you setting Diagram.Model? Are you starting off with an empty model and then later adding nodes – if so, how?

Yes,
Diagram.Model i set and after that, and getting nodes info from database in thread, they are added to model synchronized with the main thread.

Model.StartTransaction(“xxx”);
PlanModel.Links.Clear();
PlanModel.Nodes.Clear();
lock (_lock)
{
foreach (var node in nodes)
{
var nodeModel = new NodeDiagramModel(node);
UpdateDynamicPinPrefixes(nodeModel);
PlanModel.Nodes.Add(nodeModel);
}
foreach (var link in links)
{
link.PlanLogicControllerId = LogicControllerId;
PlanModel.Links.Add(new ConfigLinkDiagramModel(link));
}
PlanModel.UpdateMaxPriority(PlanModel.Links.Count);
foreach (var note in notes)
{
PlanModel.Nodes.Add(new ConfigNoteDataModel(note));
}
}
Model.CommitTransaction(“xxx”);
Model.IsModified = false;

I also update link routes on Diagram.LayoutCompleted event. And that’s all.

What is PlanModel? Why are you clearing it outside of the lock? Why are the transaction calls outside of the lock?

This lock was only for test purpose. It is not used any more. Plan model is your ILinksModel. This code is used in a ViewModel which updates View binded properties.

I do not understand your code. There is no Nodes property on ILinksModel or GraphLinksModel. And clearly you have additional methods on this PlanModel.

Which properties/attributes have you set/bound on your Diagram, and to what values? What about event handlers or method overrides?

Yes you are right. Sorry for my mistake. Its a ViewModel which has two properties:
public ObservableCollection Links { get; private set; }

    public ObservableCollection<DiagramItemModelBase> Nodes { get; private set; }

They are binded to IDiagramModel.NodesSource and IDiagramModel.LinksSource.

OK, so they are just collections of data.

What about Diagram property settings and event handlers?

Diagram XAML properties:

           AllowRelink="True"
            AllowLink="True" 
            AllowDrop="True"
            AllowScroll="True"
            AllowZoom="True"
            Padding="80, 30, 30, 30"
            VerticalContentAlignment="Top"
            HorizontalContentAlignment="Left"

Initialization in CommandHandler :

   protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);
        Diagram.UnloadingClearsPartManager = false;
        Diagram.SelectionMoved += DiagramSelectionMoved;
        Diagram.NodeResized += Diagram_NodeResized;
        Diagram.PreviewMouseDoubleClick += DiagramPreviewMouseDoubleClick;
        Diagram.LinkReshaped += DiagramLinkReshaped;
        Diagram.LinkRelinked += DiagramLinkRelinked;
        Diagram.MouseRightButtonUp += DiagramMouseRightButtonUp;
        Diagram.MouseRightButtonDown += DiagramOnMouseRightButtonDown;
        Diagram.MouseLeftButtonUp += DiagramOnMouseLeftButtonDownEvent;
        Diagram.MouseMove += DiagramOnMouseMove;
        Diagram.AllowCopy = false;
        Diagram.DragSelectingTool.Delay = 0;
    }

And - as I mentioned it before, before the update transaction:

    Diagram.LayoutCompleted += DoOnLayoutComplete;

and in this event handler:

    private void DoOnLayoutComplete(object sender, DiagramEventArgs e)
    {
        Diagram.LayoutCompleted -= DoOnLayoutComplete;
        foreach (Link link in Diagram.Links)
        {
            var d = link.Data as ConfigLinkDiagramModel;
            if (d == null || d.Points == null) continue;
            link.Route.Points = d.Points.ToList();
        }
    }

We update link routes.

What do DiagramOnMouseLeftButtonDownEvent and DiagramOnMouseMove do?

Are there any handled exceptions that occur?

These methods are used for copy-paste tasked functions. But they are try…catched and I tested them. There are no exceptions in there in runtime when loading the diagram.

Is there any method to repaint the diagram after it renders the first time?

I still do not understand the cause of the problem.

I suppose you could implement a Diagram.InitialLayoutCompleted handler that calls Begin
Invoke
on an action that calls Diagram.Panel.UpdateDiagramBounds(). But I am not entirely confident that will help.

Have you set any properties or event handlers on the DiagramPanel? Have you specified a Diagram.Template or fiddled with the ScrollViewer?

Ok, so we do not use any methods or events from DiagramPanel. And there are no ScrollViewers or Templates for the Diagram itself. We have only made templates for nodes and links.

I have tried to run UpdateDiagramBounds on InitialLayoutComplete, also with a special delay - but this does not help as you said:

private void DiagramOnInitialLayoutCompleted(object sender,

     DiagramEventArgs e)
    {
        Task.Run(() =>
        {
            Thread.Sleep(1500);
            var act = new Action(() =>
            {
                Diagram.Panel.UpdateDiagramBounds();
            });
            Dispatcher.BeginInvoke(act);
        });
    }

There is a small issue also, when rendering the largest nodes. After the diagram appears, in some cases these big nodes are not visible. After the use of scrolls (vertical or horizontal) big nodes appear. I have checked, that we do not make any Diagram changes at that perdiod of time. Maybe these two things are connected?

The last behavior you describe is also very suspicious. You might want to check, at least for those large nodes, whether their Node.Bounds matches the bounds that they should have before and after they show up after scrolling.

Ok. I try to check that.

Yes. I’ve checked it.
After thie diagram is initialized, this specific node has bounds:
{-784;2431,04;130;63,92}
After scrolling down, this node appears with new bounds:
{-784;1315,08;130;2295,84}

I’ve checked that, and we are binding only Location from ViewModel. Width and Height are set from the node template.

Normally, scrolling (or panning) and zooming (or scaling) the diagram will have no effect on any Node or Link’s bounds, which are always in model coordinates. This makes scrolling and zooming very fast.

So you must have implemented some behavior to change some nodes’ bounds. That is usually done in a DiagramPanel.ViewportBoundsChanged event handler. Do you have such a handler? Or what customizations have you done with your DiagramPanel, i.e. the value of Diagram.Panel after the ControlTemplate has been applied to the Diagram control?

I have double checked. None of these operations we make. We don’t use in any place in code Diagram.Panel property.

I cannot explain that odd behavior. Is there any way for me to reproduce the problem?

I will prepare a sample app next week for you to reproduce this problem.