Diagram looks bad when expanding group during drag

Hi,

I wanted to add an ability that when I drag a node in the diagram over a group then the group will expand so I could drop the item inside.
I added that ability by creating my own drag tool and by adding the flowing code in the DragOver function

// if we are over a closed group with the mouse then we open it
Group overNode = Diagram.Panel.FindElementAt(pt, Part.FindAncestor, x => x is Group, SearchLayers.Nodes) as Group;

if (overNode != null)
{
<span =“Apple-tab-span” style=“white-space:pre”> if (!overNode.IsExpandedSubGraph)
<span =“Apple-tab-span” style=“white-space:pre”> {
<span =“Apple-tab-span” style=“white-space:pre”> overNode.IsExpandedSubGraph = true;
<span =“Apple-tab-span” style=“white-space:pre”> }
}

It work but the diagram looks really bad (see pictures below) until the end of the drop.
Can you help me?

Before drag:

During the drag:

What I expect to see during the drag:

Is what you are complaining about the fact that when expanded it isn’t laid out nicely?
Have you have already included “GroupSizeChanged” (and perhaps other conditions) in the DiagramLayout.Conditions?

If so, perhaps the layout hasn’t happened because it’s still during a drag-and-drop, so it hasn’t had the chance to perform a layout. I’m just speculating what the problem might be. If that is the case, you could try performing the layout immediately. I haven’t tried this, but you could try calling myDiagram.LayoutManager.LayoutDiagram(LayoutInitial.None, true).

"Is what you are complaining about the fact that when expanded it isn't laid out nicely?" yes.
I set the Conditions to "All"
<Layout:TreeLayout x:Key="FlowCanvasDiagramLayout" Conditions="All" Angle="90"
SetsPortSpot="False" SetsChildPortSpot="False"
LayerSpacing="20" TreeStyle="Layered" x:Shared="False"/>
by code
Diagram.SetResourceReference(Diagram.LayoutProperty, LayoutResourceKey); and in the template

<Grid go:Node.LocationElementName="myGroupPanel"
go:Node.LocationSpot="TopLeft"
go:Node.SelectionElementName="myGroupPanel"
go:Group.Layout="{StaticResource FlowCanvasDiagramLayout}" I tried to use in the DragOver function:
Diagram.LayoutManager.LayoutDiagram(LayoutInitial.InvalidateIfNodesUnlocated, true);
and
Diagram.LayoutManager.LayoutDiagram(LayoutInitial.InvalidateAll, true); but still I get:
in LayoutInitial.InvalidateIfNodesUnlocated:
in LayoutInitial.InvalidateAll
Do you have any ideas how to solve it?

I’m surprised that you can share the Diagram.Layout and the Group.Layout by referring to the same resource. I’m concerned that using the same TreeLayout for all Group instances might cause a problem. Are there no warnings in the trace listener output (e.g. Visual Studio Output window)?

I suggest that you put the XAML inline into the Group template, and separately for the Diagram. I don’t know if that will fix the problem, but at least it’s suspicious.

I don’t share the resource because it have a property of <span =“Apple-style-span” style=": rgb248, 248, 252; “>x:Shared=“False” but i did what you said and Put the XAML inline in the group template but it didn’t fix the problem.
<span =“Apple-style-span” style=”: rgb248, 248, 252; “>Do you have any ideas how to fix it?
<span =“Apple-style-span” style=”: rgb248, 248, 252; ">Thanks,

Is everything laid out nicely when the user just expands or collapses groups when not dragging?

Yes

OK, I just tried modifying the Local Expand sample by overriding the DraggingTool.DragOver method (and by replacing the sample’s custom ToolManager with an instance of my custom DraggingTool).

Oh, I also added a collapse/expand button to the Group DataTemplate, and set the ForceDirectedLayout.Conditions = “Standard GroupSizeChanged” for both the Group.Layout and the Diagram.Layout.

I found that it worked except that the behavior was annoying because it would snap the node I was dragging to where the layout wanted it. Here’s the tool:

public class LocallyExpandingDraggingTool : DraggingTool { protected override void DragOver(Point pt, bool moving, bool copying) { Group group = this.Diagram.Panel.FindPartAt<Node>(pt, n => !n.IsSelected, SearchLayers.Nodes) as Group; if (group != null && !group.IsExpandedSubGraph) { group.IsExpandedSubGraph = true; this.Diagram.LayoutManager.LayoutDiagram(LayoutInitial.None, true); } base.DragOver(pt, moving, copying); } }
So then I tried setting myDiagram.AllowDrop = true and myDiagram.AllowDragOut = true, and then the dragged node would only briefly fly to the place where the layout would position it, and then it would go back to where I was dragging it. So it’s basically working correctly.

I suppose it would be even better if the selected node did not participate in the layout. That could be done by customizing the layout to ignore selected nodes and links connected to selected nodes if the Diagram.CurrentTool is a DraggingTool.

i tried what you wrote and it doesn’t work.
when i use your code when i drag an item over a group the diagram looks really bad look at pictures above when i stop the drag every thing is still looking bad only after i close and open a group then the diagram looks fine.
do you have any ideas how to hanlde this problam?

I cannot tell why your application isn’t working the way you want.
When I tried to implement the functionality, as I described above, I did not encounter any such problem.
(And the problem that I did encounter made sense, given the nature of the layout moving nodes out from underneath where the mouse is.)

As a wild guess, I would try turning off layout animation, to see if that changes your results.
Set myDiagram.LayoutManager.Animated = false.

I assume you have already tried using Windows drag-and-drop (setting Diagram.AllowDrop and AllowDragOut to true) instead of using the default internal drag-and-drop – again that’s a long shot at solving your problem.

If you disable the automatic layout when a group is expanded or collapsed, does everything work correctly, even with the undesired behavior that the expanded group might cause nodes to be on top of each other?

I tried to use the Animated = false and it didn’t work.
how do you disable the automatic layout?

this problem repreduce in a small tester you send before in the forum please try to fix it there.
trag the node “Second” Above the node “Third” and you will see that the links aren’t straight even after the drop only when you collapse or exspend a node the links are fixed
maybe its the same problem i am having.

the tester code:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:go="http://schemas.nwoods.com/GoXam"
        xmlns:local="clr-namespace:WpfApplication2">
 
    <FrameworkElement.Resources>
        
        <go:BooleanStringConverter x:Key="theButtonConverter" TrueString="-" FalseString="+" />
 
        <DataTemplate x:Key="NodeTemplate">
            <go:NodePanel Sizing="Fixed" go:Part.SelectionAdorned="True">
                <Rectangle Fill="LightBlue" Stroke="Gray" StrokeThickness="2" Width="200" Height="50" />
                <TextBlock Text="{Binding Path=Data.Key}" HorizontalAlignment="Center" VerticalAlignment="Center" />
            </go:NodePanel>
        </DataTemplate>
 
        <DataTemplate x:Key="GroupTemplate">
            
            <Border CornerRadius="5" BorderBrush="DarkBlue" BorderThickness="2" 
              go:Part.SelectionAdorned="True"
              go:Node.LocationElementName="myGroupPanel"
              go:Group.IsSubGraphExpanded="False">
                <Border.Background>
                    <SolidColorBrush Color="Black" Opacity="0.06" />
                </Border.Background>
                <StackPanel>
                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" MinWidth="200">
                        <Button x:Name="myCollapseExpandButton" Click="CollapseExpandButton_Click"
                Content="{Binding Path=Group.IsExpandedSubGraph, Converter={StaticResource theButtonConverter}}"
                Width="20" Margin="0 0 5 0" />
                        <TextBlock Text="{Binding Path=Data.Key}" FontWeight="Bold" />
                    </StackPanel>
                    <go:GroupPanel x:Name="myGroupPanel" Padding="5" />
                </StackPanel>
                <go:Group.Layout>
                    <go:LayeredDigraphLayout Direction="0" />
                </go:Group.Layout>
            </Border>
        </DataTemplate>
 
        <go:DataTemplateDictionary x:Key="LinkTemplateDictionary">
            <DataTemplate x:Key="Main">
                <go:LinkShape Stroke="Black" StrokeThickness="3">
                    <go:Link.Route>
                        <go:Route Routing="Orthogonal" Corner="10" />
                    </go:Link.Route>
                </go:LinkShape>
            </DataTemplate>
 
            <DataTemplate x:Key="Extra">
                <go:LinkShape Stroke="DarkGray" StrokeThickness="2" go:Part.LayoutId="None">
                    <go:Link.Route>
                        <go:Route Curve="Bezier"
                      FromSpot="0 0.5" FromEndSegmentLength="50"
                      ToSpot="0 0.5" ToShortLength="5" FromShortLength="1" ToEndSegmentLength="50" />
                    </go:Link.Route>
                </go:LinkShape>
            </DataTemplate>
        </go:DataTemplateDictionary>
    </FrameworkElement.Resources>
 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Button Content="Layout All" Click="Button_Click" />
        </StackPanel>
        <go:Diagram Grid.Row="1" x:Name="myDiagram" Padding="10"
                BorderBrush="Green" BorderThickness="2"
                HorizontalContentAlignment="Stretch"
                VerticalContentAlignment="Stretch"
                NodeTemplate="{StaticResource NodeTemplate}"
                GroupTemplate="{StaticResource GroupTemplate}"
                LinkTemplateDictionary="{StaticResource LinkTemplateDictionary}">
            <go:Diagram.Layout>
                <go:LayeredDigraphLayout Direction="90" Conditions="All" />
            </go:Diagram.Layout>
        </go:Diagram>
    </Grid>
</Window>


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using Northwoods.GoXam.Tool;

namespace WpfApplication2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

        <span style="color:blue;">var</span> nodes = <span style="color:blue;">new</span> <span style="color:#2b91af;">ObservableCollection</span><<span style="color:#2b91af;">NodeData</span>>() {
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"first"</span>, IsSubGraph=<span style="color:blue;">false</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"second"</span>, IsSubGraph=<span style="color:blue;">true</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"third"</span>, IsSubGraph=<span style="color:blue;">true</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"fourth"</span>, IsSubGraph=<span style="color:blue;">false</span> },

    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"2a"</span>, SubGraphKey=<span style="color:#a31515;">"second"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"2b"</span>, SubGraphKey=<span style="color:#a31515;">"second"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"2c"</span>, SubGraphKey=<span style="color:#a31515;">"second"</span> },

    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"3a"</span>, SubGraphKey=<span style="color:#a31515;">"third"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">NodeData</span>() { Key=<span style="color:#a31515;">"3b"</span>, SubGraphKey=<span style="color:#a31515;">"third"</span> },
  };

        <span style="color:blue;">var</span> links = <span style="color:blue;">new</span> <span style="color:#2b91af;">ObservableCollection</span><<span style="color:#2b91af;">LinkData</span>>() {
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"first"</span>, To=<span style="color:#a31515;">"second"</span>, Category=<span style="color:#a31515;">"Main"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"second"</span>, To=<span style="color:#a31515;">"third"</span>, Category=<span style="color:#a31515;">"Main"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"third"</span>, To=<span style="color:#a31515;">"fourth"</span>, Category=<span style="color:#a31515;">"Main"</span> },

    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"2a"</span>, To=<span style="color:#a31515;">"2b"</span>, Category=<span style="color:#a31515;">"Main"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"2a"</span>, To=<span style="color:#a31515;">"2c"</span>, Category=<span style="color:#a31515;">"Main"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"3a"</span>, To=<span style="color:#a31515;">"3b"</span>, Category=<span style="color:#a31515;">"Main"</span> },

    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"2a"</span>, To=<span style="color:#a31515;">"third"</span>, Category=<span style="color:#a31515;">"Extra"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"2b"</span>, To=<span style="color:#a31515;">"3b"</span>, Category=<span style="color:#a31515;">"Extra"</span> },
    <span style="color:blue;">new</span> <span style="color:#2b91af;">LinkData</span>() { From=<span style="color:#a31515;">"2c"</span>, To=<span style="color:#a31515;">"3b"</span>, Category=<span style="color:#a31515;">"Extra"</span> },
  };

        <span style="color:blue;">var</span> model = <span style="color:blue;">new</span> <span style="color:#2b91af;">GraphLinksModel</span><<span style="color:#2b91af;">NodeData</span>, <span style="color:#2b91af;">String</span>, <span style="color:#2b91af;">String</span>, <span style="color:#2b91af;">LinkData</span>>();
        model.NodesSource = nodes;
        model.LinksSource = links;
        model.Modifiable = <span style="color:blue;">true</span>;
        myDiagram.Model = model;
        myDiagram.DraggingTool = <span style="color:blue;">new</span> <span style="color:#2b91af;">NewDraggingTool</span>();
    }

    <span style="color:blue;">private</span> <span style="color:blue;">void</span> Button_Click(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">RoutedEventArgs</span> e)
    {
        myDiagram.LayoutDiagram();
    }

    <span style="color:blue;">private</span> <span style="color:blue;">void</span> CollapseExpandButton_Click(<span style="color:blue;">object</span> sender, <span style="color:#2b91af;">RoutedEventArgs</span> e)
    {
        <span style="color:green;">// the Button is in the visual tree of a Node</span>
        <span style="color:#2b91af;">Button</span> button = (<span style="color:#2b91af;">Button</span>)sender;
        <span style="color:#2b91af;">Group</span> sg = <span style="color:#2b91af;">Part</span>.FindAncestor<<span style="color:#2b91af;">Group</span>>(button);
        <span style="color:blue;">if</span> (sg != <span style="color:blue;">null</span>)
        {
            <span style="color:#2b91af;">NodeData</span> subgraphdata = (<span style="color:#2b91af;">NodeData</span>)sg.Data;
            <span style="color:blue;">if</span> (!subgraphdata.IsSubGraph) <span style="color:blue;">return</span>;
            <span style="color:green;">// always make changes within a transaction</span>
            myDiagram.StartTransaction(<span style="color:#a31515;">"CollapseExpand"</span>);
            <span style="color:green;">// toggle whether this node is expanded or collapsed</span>
            sg.IsExpandedSubGraph = !sg.IsExpandedSubGraph;
            myDiagram.CommitTransaction(<span style="color:#a31515;">"CollapseExpand"</span>);
        }
    }
}


<span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NodeData</span> : <span style="color:#2b91af;">GraphLinksModelNodeData</span><<span style="color:#2b91af;">String</span>> { }

<span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">LinkData</span> : <span style="color:#2b91af;">GraphLinksModelLinkData</span><<span style="color:#2b91af;">String</span>, <span style="color:#2b91af;">String</span>> { }

<span style="color:blue;">public</span> <span style="color:blue;">class</span> <span style="color:#2b91af;">NewDraggingTool</span>:<span style="color:#2b91af;">DraggingTool</span>
{
    <span style="color:blue;">protected</span> <span style="color:blue;">override</span> <span style="color:blue;">void</span> DragOver(<span style="color:#2b91af;">Point</span> pt, <span style="color:blue;">bool</span> moving, <span style="color:blue;">bool</span> copying)
    {
        <span style="color:#2b91af;">Group</span> group = <span style="color:blue;">this</span>.Diagram.Panel.FindPartAt<<span style="color:#2b91af;">Node</span>>(pt, n => !n.IsSelected, <span style="color:#2b91af;">SearchLayers</span>.Nodes) <span style="color:blue;">as</span> <span style="color:#2b91af;">Group</span>;
        <span style="color:blue;">if</span> (group != <span style="color:blue;">null</span> && !group.IsExpandedSubGraph)
        {
            group.IsExpandedSubGraph = <span style="color:blue;">true</span>;
            <span style="color:blue;">this</span>.Diagram.LayoutManager.LayoutDiagram(<span style="color:#2b91af;">LayoutInitial</span>.None, <span style="color:blue;">true</span>);
        }

        <span style="color:blue;">base</span>.DragOver(pt, moving, copying);
    }
}

}

Thanks for the sample app.

But alas, I tried it in both 1.2.6 and in 1.3.1 and I was unable to reproduce any problem, besides the unrelated one that I mentioned earlier. After I set Diagram.AllowDrop=“True” and AllowDragOut=“True”, it worked fine.

I tried dragging the collapsed “Second” node over the collapsed “Third” node.
I also tried dragging a copy of the “Fourth” node over both collapsed groups.

you are right setting the AllowDragOut=“True” fixed the problem in the tester but in my application it doesn’t fix it. i will try to repreduce my problem in the tester Cry.

there are 2 more problems that repreduce in the tester.
1) when you drag the node "Second" to the end of the window the scrolling isn't smooth
2) you can keep scrolling down even after we past the last node and there is a long scroll with no meaning

(1) Maybe that’s because you set the layout Conditions=“All”. Instead, set Conditions=“Standard GroupSizeChanged”, which will avoid a lot of layouts that I think are undesirable.

(2) I don’t understand what it is that you don’t want.
Do you want to turn off autoscrolling? But your problem (1) implied that you want autoscrolling.

Changing the Conditions to GroupSizeChanged | Standard wasn't helpful is still not scrolling smooth. <?: prefix = o ns = "urn:schemas-microsoft-com:office:office" />

I want auto scroll but I want to set an upper and lower limit just like in list box you can't scroll after you reach the last item or the first item, it have no meaning and it’s annoying

Autoscrolling is implemented by a timer that changes the DiagramPanel.Position. Perhaps the increments are too large for you, so the scrolling seems too jumpy? You could try decreasing the values of DiagramPanel.ScrollVerticalLineChange and ScrollHorizontalLineChange.

The normal behavior is to allow the user to expand the size of the diagram (the DiagramPanel.DiagramBounds) by dragging the selection beyond its current bounds. That’s because diagrams are fundamentally different from ListBoxes – they are truly two-dimensional, and users can position objects whereever they want them to be.

However, if you are continually performing a layout when the user moves a node (because Conditions=“All”), I suppose that doesn’t make sense for your application. In this case you can limit the autoscrolling behavior by overriding the DiagramPanel.ComputeAutoScrollPosition method.

public class CustomDiagramPanel : DiagramPanel { protected override Point ComputeAutoScrollPosition(Point viewPnt) { var bounds = this.DiagramBounds; var view = this.ViewportBounds; var pos = base.ComputeAutoScrollPosition(viewPnt); pos.X = Math.Max(Math.Min(pos.X, bounds.Right-view.Width), bounds.X); pos.Y = Math.Max(Math.Min(pos.Y, bounds.Bottom-view.Height), bounds.Y); return pos; } }
Install by customizing the Diagram.Template:

<ControlTemplate x:Key="CustomAutoScroller" TargetType="go:Diagram"> <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True"> <local:CustomDiagramPanel x:Name="Panel" Stretch="{TemplateBinding Stretch}" Padding="{TemplateBinding Padding}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" /> </ScrollViewer> </Border> </ControlTemplate>
and setting the Template attribute on the Diagram:
Template="{StaticResource CustomAutoScroller}"

thanks walter that worked.
but i still have two problems:

  1. the scrolling is jumpy.
    <span =“Apple-tab-span” style=“white-space:pre”> how can i set the AutoScrollTime and the AutoScrollDelay? maybe they will help?
    2)i can still drag the rectanlge in the overview window out of is bounds, it block by the top left and right but the bottom isn’t block and we can drag it, see picture.
    how can i block it?

DiagramPanel.AutoScrollTime hasn’t been made public. You could try setting it by using reflection.

The “box” in the overview just shows the viewport of the observed diagram. According to the scrollbar for the main diagram, the diagram bounds does extend well below the “End” node, which is why the user was able to scroll that far, either with the scrollbar itself in the observed diagram or with the overview box in the overview.

If you look at the overview in the Org Chart (Static) sample, you can see that the user cannot scroll beyond the diagram bounds, neither in the main diagram nor in the overview window.

my problem exist in the Org Chart (Static) Demo.
it is true that in my application and in the demo the user cannot scroll beyond the diagram bound with the main diagram scroll bars, but with the overview window he can scroll down below the bounds see picture below:

Ah – that seems to have been fixed for 1.3. Sorry I was confused about which version of GoWpfDemo I was running.