Need a straight line shape in GoXam

I need to have a straight line( horizontal/vertical) in my Diagram.But the NodeFigure.Line1 or Line 2 gives me a straight line but its is a diagonal line.

How can I have a straight line in my diagram? Also this line should be resizable as required.
Thanks & Regards
Padma

I’ve added a HorizontalLine template. This is implemented in a manner very similar to how a Path with a NodePanel.Figure is implemented by a containing NodePanel.

Note that it has a custom ResizeAdornmentTemplate that creates only the two resize handles at the middle sides.

However, there appears to be a bug in being able to select it. We’ll investigate.

[code]
<UserControl.Resources>










<DataTemplate x:Key="Astronaut">
  <Border BorderBrush="Silver" BorderThickness="3" CornerRadius="5" Padding="5" Background="White">
    <StackPanel>
      <TextBlock Text="{Binding Path=Data.Text}" FontWeight="Bold" FontSize="12"/>
      <TextBlock Text="Astronaut" FontStyle="Italic" FontSize="10" />
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="Mass: " />
        <TextBlock Text="{Binding Path=Data.Mass}" />
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="Weight: " />
        <TextBlock Text="{Binding Path=Data.CurrentWeight}" />
      </StackPanel>
    </StackPanel>
  </Border>
</DataTemplate>

<DataTemplate x:Key="RaceCarDriver">
  <Border BorderBrush="Red" BorderThickness="3" Padding="5" Background="White">
    <StackPanel>
      <Border Background="DarkBlue">
        <TextBlock Text="{Binding Path=Data.Text}" FontWeight="Bold" FontSize="12" Foreground="White" />
      </Border>
      <TextBlock Text="Race Car Driver" FontStyle="Italic" FontSize="10" />
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="Weight: " />
        <TextBlock Text="{Binding Path=Data.Mass}" />
      </StackPanel>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="Speed: " />
        <TextBlock Text="{Binding Path=Data.CurrentSpeed}" />
      </StackPanel>
    </StackPanel>
  </Border>
</DataTemplate>

<font color="#ff0000">[Edit: this has been replaced by a better definition, in a reply below.]</font>
<DataTemplate x:Key="HorizontalLine">
  <Path Stroke="Black" StrokeThickness="5" Stretch="Fill"
        go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"
        Width="{Binding Path=Data.Length, Mode=TwoWay}" Height="5"
        go:Part.SelectionAdorned="False" go:Part.Resizable="True">
    <Path.Data>
      <LineGeometry StartPoint="0 0" EndPoint="1 0" />
    </Path.Data>
    <go:Part.ResizeAdornmentTemplate>
      <DataTemplate>
        <go:SpotPanel>
          <Path go:NodePanel.Figure="Rectangle" go:SpotPanel.Spot="0.0 0.5" Width="6" Height="6" Fill="DodgerBlue" Stroke="Black" StrokeThickness="1" />
          <Path go:NodePanel.Figure="Rectangle" go:SpotPanel.Spot="1.0 0.5" Width="6" Height="6" Fill="DodgerBlue" Stroke="Black" StrokeThickness="1" />
        </go:SpotPanel>
      </DataTemplate>
    </go:Part.ResizeAdornmentTemplate>
  </Path>
</DataTemplate>

</UserControl.Resources>

[/code]

I’ve added a base “Item” class, with “HorizontalLine” inheriting from it.

Under the assumption that each data class will have its own DataTemplate, it’s a pain to have to maintain a DataTemplateDictionary. So I have customized the PartManager to automatically return the DataTemplate that is named the same as the class name. No DataTemplateDictionary needed!

[code]using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;

namespace SilverlightApplication1 {
public partial class MultiDataModel : UserControl {
public MultiDataModel() {
InitializeComponent();

  // instead of using and maintaining a DataTemplateDictionary,
  // implement its usage in an override of PartManager.FindTemplateForNode
  myDiagram.PartManager = new CustomPartManager();

  // create a trivial model holding one instance of each node data class
  var model1 = new GraphModel<Item, String>();
  model1.NodesSource = new List<Item>() {
    new Person() { Key="1", Text="Joe Random", Mass=50 },
    new Astronaut() { Key="2", Text="Joe Wright", Mass=50, CurrentWeight=0.01 },
    new RaceCarDriver() { Key="3", Text="Fast Joe", Mass=50, CurrentSpeed=203 },

    new HorizontalLine() { Key="4" },
  };
  this.Model1 = model1;

  // start off showing this model
  myDiagram.Model = this.Model1;
}

internal GraphModel<Item, String> Model1 { get; set; }

private void Button1_Click(object sender, RoutedEventArgs e) {
  myDiagram.Model = this.Model1;
}

private void Button2_Click(object sender, RoutedEventArgs e) {
  var model2 = new GraphModel<Item, String>();
  model2.NodesSource = GeneratePeople();
  myDiagram.Model = model2;
}

private IList<Item> GeneratePeople() {
  var people = new List<Item>();
  Random rand = new Random();
  int num = rand.Next(10) + 3;
  for (int i = 0; i < num; i++) {
    Person p;
    switch (rand.Next(3)) {
      case 1: p = new Astronaut() { Category="Astronaut" }; break;
      case 2: p = new RaceCarDriver() { Category="RaceCarDriver" }; break;
      default: p = new Person() { Category="" }; break;
    }
    p.Key = i.ToString();
    p.Text = "Person #" + i.ToString();
    p.Mass = rand.Next(100);
    people.Add(p);
  }
  return people;
}

}

public abstract class Item : GraphModelNodeData { }

public class Person : Item {
public double Mass {
get { return _Mass; }
set {
if (_Mass != value) {
double old = _Mass;
_Mass = value;
RaisePropertyChanged(“Mass”, old, value);
}
}
}
private double _Mass;
}

public class Astronaut : Person {
public double CurrentWeight {
get { return _CurrentWeight; }
set {
if (_CurrentWeight != value) {
double old = _CurrentWeight;
_CurrentWeight = value;
RaisePropertyChanged(“CurrentWeight”, old, value);
}
}
}
private double _CurrentWeight;
}

public class RaceCarDriver : Person {
public double CurrentSpeed {
get { return _CurrentSpeed; }
set {
if (_CurrentSpeed != value) {
double old = _CurrentSpeed;
_CurrentSpeed = value;
RaisePropertyChanged(“CurrentSpeed”, old, value);
}
}
}
private double _CurrentSpeed;
}

public class HorizontalLine : Item {
public double Length {
get { return _Length; }
set {
if (_Length != value) {
double old = _Length;
_Length = value;
RaisePropertyChanged(“Length”, old, value);
}
}
}
private double _Length = 100;
}

public class CustomPartManager : PartManager {
// If we assume each data class has a different DataTemplate,
// this is easier than having to maintain a DataTemplateDictionary.
// However, this way can’t arbitrarily use different templates for each instance of any class.
protected override DataTemplate FindTemplateForNode(object nodedata, IDiagramModel model, bool isgroup, bool islinklabel, string category) {
String classname = nodedata.GetType().Name;
DataTemplate template = Diagram.FindResource(this.Diagram, classname);
return template ?? base.FindTemplateForNode(nodedata, model, isgroup, islinklabel, category);
}
}
}[/code]

Yes, I observed some problem when I select the Horizontal line after selecting it from the panel.

Its getting disappeared soon after I resize it and release mouse button.
Did you find the fix for this?
Thanks & Regards
Padma

Not yet – it appears to be a bug/misfeature in Silverlight’s VisualTreeHelper. We’re working on it.

One of us has discovered that wrapping the Path in a NodePanel or Border seems to fix all of the selection problems with a HorizontalLine in Silverlight.

Here’s the updated template:

<DataTemplate x:Key="HorizontalLine"> <Border go:Part.SelectionElementName="Shape" go:Part.SelectionAdorned="True" go:Part.Resizable="True" go:Node.Location="{Binding Path=Data.Location, Mode=TwoWay}"> <Path x:Name="Shape" Stroke="Black" StrokeThickness="3" Stretch="Fill" Width="{Binding Path=Data.Length, Mode=TwoWay}"> <Path.Data> <LineGeometry StartPoint="0 0" EndPoint="1 0" /> </Path.Data> </Path> <go:Part.ResizeAdornmentTemplate> <DataTemplate> <go:SpotPanel> <!-- use go:ToolHandle in WPF, Path in Silverlight --> <Path go:NodePanel.Figure="Rectangle" go:SpotPanel.Spot="0.0 0.5" Width="6" Height="6" Fill="DodgerBlue" Stroke="Black" StrokeThickness="1" /> <Path go:NodePanel.Figure="Rectangle" go:SpotPanel.Spot="1.0 0.5" Width="6" Height="6" Fill="DodgerBlue" Stroke="Black" StrokeThickness="1" /> </go:SpotPanel> </DataTemplate> </go:Part.ResizeAdornmentTemplate> </Border> </DataTemplate>
This template is for Silverlight. For WPF, replace the two Paths in the ResizeAdornmentTemplate with go:ToolHandle.