Custom node creation and processing

I have created a custom object switch using the following code in GoSilverlight application.
<go:NodePanel>
<Path Stroke="{Binding Path=Node.IsSelected,
Converter={StaticResource theSelectionConverter}}" StrokeThickness=“1” Margin=“10,30,40,5”>
<Path.Data>
<GeometryGroup>
<EllipseGeometry RadiusX=“5” RadiusY=“5”/>
<LineGeometry StartPoint=“0,0” EndPoint=“25,0”>
<LineGeometry.Transform>
<RotateTransform Angle="-30"/>
</LineGeometry.Transform>
</LineGeometry>
<EllipseGeometry RadiusX=“5” RadiusY=“5” Center=“25,0”/>
<EllipseGeometry RadiusX=“2.5” RadiusY=“2.5” Center=“21,-12”/>
</GeometryGroup>
</Path.Data>
</Path>
</go:NodePanel>
which typically results into a switch node being displayed on the page. But when i try to move this node, I could not able to do as similar to other nodes provided by GoSilverlight.

Could anyone let us know,can i access individual components of the above geometric group and have some transformations applied to them individually? For ex: the line in my geometry group can be accessed and we should be able to set transformation (rotation) angles.
Thanks & Regards
Padma

When I created several nodes using the above template, I was able to select and drag them around.

However, please note that there is no Fill for the Path element, so clicking in the middle of those “open” ellipses will not “find” that Path. If you really want your ellipses to be transparent, set the Fill=“Transparent”.

Part.VisualElement for any Node will return the root visual of the node. In this case it will be a NodePanel. You can then traverse or search the visual tree to find the Path. You can get its Path.Data and traverse that Geometry to find the particular LineGeometry that you want to transform.

I assume you have simplified this node template from the actual definition. There’s no need to use a NodePanel when there’s just one child element.

Also, the Margin you specify probably doesn’t have any effect unless there are other child elements in the panel.

Even after setting Fill to Transparent, there is no change in the drag and drop of the node. Its taking hell lot of time to select the custom switch node created.
Coming to traverse , I did not get you completely how to traverse a Diagram. Could you please illustrate with an exampke?


<UserControl.Resources>
<local:LineTerminationConverter x:Key=“theLineTerminationConverter” />

<DataTemplate x:Key="SwitchTemplate">
  <Canvas Width="35" Height="30"
          go:Part.SelectionAdorned="True"
          go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"
          MouseLeftButtonDown="Canvas_MouseLeftButtonDown">
    <Rectangle Canvas.Left="0" Canvas.Top="0" Width="35" Height="30"
               Fill="Transparent" />
    <Ellipse Canvas.Left="15" Canvas.Top="0" Width="5" Height="5"
             Stroke="Black" StrokeThickness="1" Fill="LightGray"
             go:Node.PortId="In" go:Node.ToSpot="MiddleTop"
             go:Node.LinkableTo="True" go:Node.LinkableMaximum="1" />
    <Ellipse Canvas.Left="0" Canvas.Top="20" Width="10" Height="10"
             Stroke="Black" StrokeThickness="1" Fill="LightGray"
             go:Node.PortId="Out1" go:Node.FromSpot="MiddleBottom"
             go:Node.LinkableFrom="True" />
    <Ellipse Canvas.Left="25" Canvas.Top="20" Width="10" Height="10"
             Stroke="Black" StrokeThickness="1" Fill="LightGray"
             go:Node.PortId="Out2" go:Node.FromSpot="MiddleBottom"
             go:Node.LinkableFrom="True" />
    <Line Canvas.Left="0" Canvas.Top="0" X1="17.5" Y1="2.5" Y2="25"
          X2="{Binding Path=Data.Output, Converter={StaticResource theLineTerminationConverter}}"
          Stroke="Black" StrokeThickness="1" />
  </Canvas>
</DataTemplate>

<DataTemplate x:Key="WireTemplate">
  <Path Stroke="Black" StrokeThickness="2">
    <go:Link.Route>
      <go:Route Routing="AvoidsNodes" />
    </go:Link.Route>
  </Path>
</DataTemplate>

</UserControl.Resources>

/* Copyright © Northwoods Software Corporation, 2008-2010. All Rights Reserved. */

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

namespace SwitchGraphic {
public partial class SwitchGraphic : UserControl {
public SwitchGraphic() {
InitializeComponent();

  var model = new GraphLinksModel<SwitchData, String, String, WireData>();
  model.NodesSource = new ObservableCollection<SwitchData>() {
    new SwitchData() { Key="First", Output=1 },
    new SwitchData() { Key="Second", Output=2 },
    new SwitchData() { Key="Unassigned" },
  };
  model.LinksSource = new ObservableCollection<WireData>() {
    new WireData() { From="First", FromPort="Out1", To="Second", ToPort="In" },
  };
  model.Modifiable = true;
  model.HasUndoManager = true;
  myDiagram.Model = model;
}

private void Canvas_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
  if (DiagramPanel.IsDoubleClick(e)) {
    // walk up visual tree from double-clicked element to find the Node
    Node n = Part.FindAncestor<Node>(e.OriginalSource as UIElement);
    if (n != null) {
      SwitchData d = n.Data as SwitchData;
      if (d != null) {
        myDiagram.StartTransaction("toggle switch");
        switch (d.Output) {
          case 1: d.Output = 2; break;
          case 2: d.Output = 1; break;
          default: d.Output = 1; break;  // if unassigned, start with Output 1
        }
        myDiagram.CommitTransaction("toggle switch");
      }
    }
  }
}

}

// convert a SwitchData.Output value to an X-coordinate line endpoint value
public class LineTerminationConverter : Converter {
public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if (value is int) {
switch ((int)value) {
case 1: return 5;
case 2: return 30;
default: return 17.5;
}
}
return 17.5;
}
}

public class SwitchData : GraphLinksModelNodeData {
public int Output {
get { return _Output; }
set {
if (_Output != value) {
int old = _Output;
_Output = value;
RaisePropertyChanged(“Output”, old, value);
}
}
}
private int _Output;
}

public class WireData : GraphLinksModelLinkData<String, String> {
}
}