The node after a rotation is below the name

When we rotate a node, the parent element does not change its height and width. So we have an outgoing node of the parent container.
As you can see below, we modify the code of Draggable link to show you our problem.

<go:SpotPanel
go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"
go:Node.LocationSpot=“Center”
go:Part.SelectionAdorned=“True”
go:Part.SelectionAdornmentTemplate="{StaticResource NodeSelectionAdornmentTemplate}"
go:Part.Resizable=“True”
go:Part.ResizeElementName=“Icon”
go:Part.ResizeAdornmentTemplate="{StaticResource NodeResizeAdornmentTemplate}"
go:Node.RotationAngle="{Binding Path=Data.Angle, Mode=TwoWay}"
go:Part.Rotatable=“True”
go:Part.SelectionElementName=“Icon”
go:Part.RotateAdornmentTemplate="{StaticResource NodeRotateAdornmentTemplate}">
<go:NodePanel Background=“Blue”>

<go:NodeShape x:Name=“Icon”
go:NodePanel.Figure="{Binding Path=Data.Figure}"
Stroke=“Black” StrokeThickness=“1”
Fill="{Binding Path=Data.Color}"
Width="{Binding Path=Data.Width, Mode=TwoWay}"
Height="{Binding Path=Data.Height, Mode=TwoWay}"
MinWidth=“10” MinHeight=“10”
go:NodePanel.Spot1=“0 0” go:NodePanel.Spot2=“1 1”
go:Node.PortId="" go:Node.LinkableFrom=“True” go:Node.LinkableTo=“True” Cursor=“Hand”
go:Node.LinkableDuplicates=“True” go:Node.LinkableSelfNode=“True” />


</go:NodePanel>




</go:SpotPanel>

The pictures below represent the problem we have.

After some research when I set a RotateTransform to the RenderTransform property of a StackPanel, we have the same result as GoXam. However when I set RotateTransform to the LayoutTransform property of a StackPanel, we have the right result.
How Goxam can have the same behavior as a LayoutTransform?

It appears that you want to rotate the shape (the NodeShape named “Icon”), and you don’t want to rotate the SpotPanel and its Rectangle ports, is that right?

So what do you want to do? I don’t see what the problem is.

I want to rotate the NodeShape with the background that fits its content. The problem is that the StackPanel doesn’t fit with his content.
I did some tests with StackPanel representing both situations.

First test, I applied RotateTransform(90, Rectagle.Width / 2, Rectagle.Height / 2) to the RederTransform of my stackPanel.
I obtained this result and it’s the same as GoXam.

Second test, I applied RotateTransform(90, Rectagle.Width / 2, Rectagle.Height / 2) to the LayoutTransform of my stackPanel.
I obtained this result and it’s the result I would like to get inside GoXam.
As you will see, The StackPanel(Green) is below the shape (blue) and his node name and its dimensions fit with his content.

this is my Xaml Code
<StackPanel VerticalAlignment=“Center”>
<<StackPanel Background=“Green” VerticalAlignment=“Center” HorizontalAlignment=“Center”>
<StackPanel x:Name=“Rectagle” Background=“Blue” Width=“200” Height=“50”>
<TextBlock Text=“Test” HorizontalAlignment=“Center”>
</StackPanel>
<Button Margin=“50” Click=“Button_Click” Width=“100” Content=“Set angle to 90”>
</StackPanel>

  • I applied the RotateTransform to the Rectagle.RenderTransform and to the Rectagle.LayoutTransform to create both behaviors.

Ah, I understand you now. OK, it is true that the default behavior of Part.GetAngle and Part.SetAngle deal with the RenderTransform and not the LayoutTransform. I haven’t tried this, but I believe you can override those two methods on your Nodes.

Here’s how they are currently implemented. Pardon me if there are some internal dependencies in this code:

    public virtual double GetAngle(UIElement elt) {
      if (elt == null) elt = this.VisualElement;
      if (elt == null) return 0;
      Transform transform = elt.RenderTransform;
      RotateTransform rt = transform as RotateTransform;
      TransformGroup tg = transform as TransformGroup;
      if (rt == null && tg != null) {
        foreach (Transform t in tg.Children) {
          rt = t as RotateTransform;
          if (rt != null) break;
        }
      }
      if (rt != null) return rt.Angle;
      return 0;
    }
    public virtual void SetAngle(UIElement elt, double angle, Spot focus) {
      SetAngleAndScale(elt, angle, focus, new Size(1, 1));
    }

    internal void SetAngleAndScale(UIElement elt, double angle, Spot focus, Size scale) {
      if (elt == null) elt = this.VisualElement;
      if (elt == null) return;
      if (Double.IsNaN(angle) || Double.IsInfinity(angle)) angle = 0;
      double scaleX = scale.Width;
      if (Double.IsNaN(scaleX) || Double.IsInfinity(scaleX)) scaleX = 1;
      double scaleY = scale.Height;
      if (Double.IsNaN(scaleY) || Double.IsInfinity(scaleY)) scaleY = 1;

      // handle most common case, especially for speed in Get[Relative]Element(Point/Bounds)
      if (angle == 0 && scaleX == 1 && scaleY == 1) {
        elt.RenderTransform = null;
        elt.RenderTransformOrigin = new Point(0, 0);
      } else {
        if (!(this is Adornment)) {
          if (focus.IsNoSpot) focus = Spot.Center;
          elt.RenderTransformOrigin = new Point(focus.X, focus.Y);
        }

        // try to find an existing transforms
        Transform transform = elt.RenderTransform;
        TransformGroup tg = transform as TransformGroup;
        // try to find an existing RotateTransform
        RotateTransform rt = transform as RotateTransform;
        if (rt == null && tg != null) {
          foreach (Transform t in tg.Children) {
            rt = t as RotateTransform;
            if (rt != null) break;
          }
        }
        // try to find an existing ScaleTransform
        ScaleTransform st = transform as ScaleTransform;
        if (st == null && tg != null) {
          foreach (Transform t in tg.Children) {
            st = t as ScaleTransform;
            if (st != null) break;
          }
        }

        RotateTransform rt2 = null;
        ScaleTransform st2 = null;
        if (rt != null && !rt.IsFrozen) {
          rt.Angle = angle;
        } else if (angle != 0) {
          rt2 = new RotateTransform();
          rt2.Angle = angle;
        }
        if (st != null && !st.IsFrozen) {
          st.ScaleX = scaleX;
          st.ScaleY = scaleY;
        } else if (scaleX != 1 || scaleY != 1) {
          st2 = new ScaleTransform();
          st2.ScaleX = scaleX;
          st2.ScaleY = scaleY;
        }

        TransformGroup newtg = null;
        if (rt2 != null && st2 != null) {
          newtg = new TransformGroup();
          newtg.Children.Add(st2);
          newtg.Children.Add(rt2);
          elt.RenderTransform = newtg;
        } else if (rt2 != null) {
          newtg = new TransformGroup();
          newtg.Children.Add(rt2);
          if (st != null)
            newtg.Children.Add(st);
          elt.RenderTransform = newtg;
        } else if (st2 != null) {
          newtg = new TransformGroup();
          if (rt != null)
            newtg.Children.Add(rt);
          newtg.Children.Add(st2);
          elt.RenderTransform = newtg;
        }
      }

      Node node = this as Node;
      if (node != null) {
        if (elt == node.SelectionElement) {
          // save the angle as the RotationAngle attached property
          Node.SetRotationAngle(node.VisualElement, angle);
          // (not saving scale as an attached dependency property)
        }
        InvalidateRelationships();
      }
    }

Presumably you can adapt this code to work with the LayoutTransform.

To make use of your custom Node subclass, you’ll need to use a custom PartManager. Override this method, replacing the Node constructor with your own constructor:

    protected virtual Node MakeNodeForData(Object nodedata, IDiagramModel model, bool isgroup, bool islinklabel, String category, DataTemplate templ) {
      Node node = (isgroup ? new Group() : new Node());  // for PartManager.MakeNodeForData
      PartBinding data = new PartBinding(node, nodedata);
      node.Content = data;
      node.DataContext = data;
      node.ContentTemplate = templ;  // for PartManager.MakeNodeForData
      node.IsLinkLabel = islinklabel;
      if (category != null && category != "") {
        if (node.Category != category) node.Category = category;
      }
      return node;
    }

I hope this is enough information for you to accomplish what you want.

Can it be possible to have the implementation of the method Part.ClearCachedValues because it’s required when I create SetAngleAndScale.

Sorry – I missed that call. I’ll look it up when I get back to my development machine.

No problem thank alot for your help

We’re in luck – in WPF that method is a no-op. I’ll delete the call from the code above.

Thank you, the solution works fine