Node expand/collapse issue

I am trying to use expand/collapse feature for nodes as shown below:

When I click plus button to expand it sometimes I get nodes overlapped as shown below:
Here is the xaml:
<UserControl x:Class="SLDeviceDatacontract.Views.NetworkTopologyView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:go="clr-namespace:Northwoods.GoXam;assembly=Northwoods.GoSilverlight" xmlns:golayout="clr-namespace:Northwoods.GoXam.Layout;assembly=Northwoods.GoSilverlight" xmlns:Converters="clr-namespace:SLDeviceDatacontract.Converters" xmlns:cmd="clr-namespace:Microsoft.Practices.Prism.Commands;assembly=Microsoft.Practices.Prism" Name="netview"> <FrameworkElement.Resources> <Converters:BoolToColorConverter x:Key="boolToColorConverter"/> <Converters:TextImageSourceConverter x:Key="textImageSourceConverter"/> <Converters:BoolToVisibilityConverter x:Key="boolToVisibilityConverter"/> <Converters:BoolToCollapseConverter x:Key="boolToCollapseConverter"/> <Converters:HasChildrenVisibilityConverter x:Key="hasChildrenVisibilityConverter"/>

<go:BooleanStringConverter x:Key=“theButtonConverter” TrueString="-" FalseString="+" />
<Style x:Key=“diagramStyle” TargetType=“go:Diagram”>
<Setter Property=“Padding” Value=“10”/>
<Setter Property=“Grid.Column” Value=“1”/>
<Setter Property=“Grid.Row” Value=“0”/>
<Setter Property=“Background” Value=“White”/>
<Setter Property=“VerticalContentAlignment” Value=“Top”/>
<Setter Property=“HorizontalContentAlignment” Value=“Center”/>
<Setter Property=“VerticalAlignment” Value=“Top”/>
<Setter Property=“HorizontalAlignment” Value=“Center”/>
<Setter Property=“AllowScroll” Value=“False”/>

<Setter Property=“Grid.Column” Value=“1”/>
</Style>
<Style TargetType=“TextBlock”>
<Setter Property=“Foreground” Value=“Black”/>
<Setter Property=“FontSize” Value=“12”/>
<Setter Property=“Margin” Value=“10, 10, 5,0”/>
</Style>
<Style x:Key=“TextBlockStyle” TargetType=“TextBlock”>
<Setter Property=“FontSize” Value=“13”/>
</Style>
<Style x:Key=“ButtonStyle” TargetType=“Button”>
<Setter Property=“Background” Value=“White”/>
</Style>
 
 
 
<DataTemplate x:Key=“NodeTemplate”>
<go:NodePanel go:Part.SelectionAdorned=“True” go:Node.LocationSpot=“Center” go:Node.ToSpot=“MiddleTop”>
<Button cmd:Click.Command="{Binding DataContext.GoToDeviceCommand, ElementName=netview}"
cmd:Click.CommandParameter="{Binding Path=Data.Key}">

<StackPanel>
<Image Source="{Binding Path=Data.Picture, Converter={StaticResource textImageSourceConverter}}"
Width=“20” Height=“20” />
<TextBlock Text="{Binding Path=Data.FriendlyName}" FontSize=“13” Padding=“3,0,3,0”/>
<Button Click=“CollapseExpandButton_Click” x:Name=“myCollapseExpandButton”
Content="{Binding Path=Node.IsExpandedTree,
Converter={StaticResource theButtonConverter}}" Width=“20” Margin=“0 0 5 0”
Visibility="{Binding Path=Data.NumberOfChildren, Converter={StaticResource hasChildrenVisibilityConverter}}"/>

</StackPanel>
</Button>
</go:NodePanel>
</DataTemplate>
<DataTemplate x:Key=“LinkTemplate”>
<go:LinkPanel go:Part.SelectionElementName=“Path” go:Part.SelectionAdorned=“True”>

<go:LinkShape x:Name=“Path” go:LinkPanel.IsLinkShape=“True” Stroke=“Black” StrokeThickness=“1”/>
<go:Link.Route>
<go:Route Routing=“AvoidsNodes” Adjusting=“Scale”/>
</go:Link.Route>
</go:LinkPanel>
</DataTemplate>

<go:DataTemplateDictionary x:Key=“NodeTemplates” />
 
</FrameworkElement.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height=“0” />
<RowDefinition Height="" />
<RowDefinition Height=“Auto”/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=“220”/>
<ColumnDefinition Width="
"/>
<ColumnDefinition Width=“Auto”/>
</Grid.ColumnDefinitions>
 
 
<ListBox x:Name=“deviceListBox” Grid.RowSpan=“2” ItemsSource="{Binding Devices}"
HorizontalAlignment=“Stretch” HorizontalContentAlignment=“Stretch” VerticalAlignment=“Stretch” VerticalContentAlignment=“Stretch”
Margin=“5,45,15,5”>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment=“Stretch” Width=“210”>
<Button Cursor=“Hand” cmd:Click.Command="{Binding DataContext.GoToDeviceCommand, ElementName=deviceListBox}"
cmd:Click.CommandParameter="{Binding Key}" HorizontalAlignment=“Stretch” HorizontalContentAlignment=“Stretch”
VerticalContentAlignment=“Center” Background=“Transparent”>
<TextBlock TextWrapping=“Wrap” Text="{Binding FriendlyName}" HorizontalAlignment=“Stretch” Style="{StaticResource TextBlockStyle}" Margin=“5,0,0,0” />
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
 
 

<go:Diagram x:Name=“myWholeView” Grid.Row=“0”
SelectionChanged=“DiagramSelectionChanged”
IsReadOnly=“True”
Stretch=“UniformToFill”
HorizontalContentAlignment=“Center”
VerticalContentAlignment=“Center”
NodeTemplate="{StaticResource NodeTemplate}"
LinkTemplate="{StaticResource LinkTemplate}"
MaximumSelectionCount=“1”>
<go:Diagram.Layout>
<golayout:LayeredDigraphLayout Direction=“90” SetsPortSpots=“True” LayerSpacing=“25” />
</go:Diagram.Layout>

<!–<go:Node Id=“Highlight”>
<Ellipse Width=“1” Height=“1”
go:Part.LayerName=“Background”
go:Part.InDiagramBounds=“False”

go:Part.Selectable=“False”
go:Node.LocationSpot=“Center”>
<Shape.Fill>




</Shape.Fill>

</go:Node>–>
</go:Diagram>

<go:Diagram x:Name=“myLocalView” Grid.Row=“1” Grid.Column=“1”
NodeTemplate="{StaticResource NodeTemplate}"
LinkTemplate="{StaticResource LinkTemplate}" >
<go:Diagram.Layout >
<golayout:LayeredDigraphLayout Direction=“90” SetsPortSpots=“True” LayerSpacing=“15” />
</go:Diagram.Layout>
</go:Diagram>
</Grid>
</UserControl>

Here is the code behind:
using System.Windows; using System.Windows.Controls; using Northwoods.GoXam; using SLDeviceDatacontract.Models; namespace SLDeviceDatacontract.Views { public partial class NetworkTopologyView : UserControl { public NetworkTopologyView() { InitializeComponent(); ViewModel = new NetworkTopologyViewModel(this); }   public NetworkTopologyViewModel ViewModel { get { return (NetworkTopologyViewModel)this.DataContext; } set { DataContext = value; } }   /// /// Whenever any Node is selected, make sure we focus on its data /// /// /// private void DiagramSelectionChanged(object sender, SelectionChangedEventArgs e) { var diagram = (Diagram)sender; if (diagram.SelectedNode != null) { var device = diagram.SelectedNode.Data as Device; ViewModel.FocusOn(device); } }   private void CollapseExpandButton_Click(object sender, RoutedEventArgs e) { // the Button is in the visual tree of a Node Button button = (Button)sender; Node n = Part.FindAncestor<Node>(button); if (n != null) { Device parentdata = (Device)n.Data; ViewModel.FocusOn(parentdata); myWholeView.StartTransaction("CollapseExpand"); // toggle whether this node is expanded or collapsed n.IsExpandedTree = !n.IsExpandedTree; myWholeView.CommitTransaction("CollapseExpand"); } } } }
Here is the viewmodel:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Windows; using Microsoft.Practices.Prism.Commands; using Microsoft.Practices.Prism.ViewModel; using Northwoods.GoXam; using Northwoods.GoXam.Model; using SLDeviceDatacontract.Models; using System.Diagnostics.Contracts; namespace SLDeviceDatacontract.Views { public class NetworkTopologyViewModel : NotificationObject { private readonly NetworkTopologyView _view; #region Constructor public NetworkTopologyViewModel(NetworkTopologyView view) { GoToDeviceCommand = new DelegateCommand<string>(GoToDevice); _view = view;

GraphLinksModel = new NetworkTopologyService().GetDevices();
}
 
 
#region GoToDeviceCommand
///


/// Command is used to select a specific device
///

public DelegateCommand<string> GoToDeviceCommand { get; private set; }
#endregion
#region GoToDevice
///
/// This method is used to select a device by the GotToDeviceCommand
///

///
public void GoToDevice(string key)
{

SetCurrentSelectedDevice(key);
}
#endregion
///


/// Find the device by key and set the ui elements values
///

///
private void SetCurrentSelectedDevice(string key)
{

Debug.Assert(!String.IsNullOrEmpty(key), “key is null or empty.”);
CurrentDevice = Devices.Where(p => p.Key == key).FirstOrDefault();
if (CurrentDevice == null) return;
FocusOn(CurrentDevice);
}
 
#region CurrentDevice
///


/// Current selected device
///

private Device _currentDevice;
public Device CurrentDevice
{
get
{
return _currentDevice;
}
set
{
if (_currentDevice == value)
return;
_currentDevice = value;
RaisePropertyChanged(() => CurrentDevice);
}
}
#endregion
#region GraphLinksModel
///
/// This property represents source of the data for the diagram
///

private GraphLinksModel<Device, String, String, LinkData> _graphLinksModel;
public GraphLinksModel<Device, String, String, LinkData> GraphLinksModel
{
get
{
return _graphLinksModel;
}
set
{
if (_graphLinksModel == value)
return;
_graphLinksModel = value;
Devices = (List<Device>)_graphLinksModel.NodesSource;
SetWholeAndLocalViews();
RaisePropertyChanged(() => GraphLinksModel);
}
}
#endregion
#region SetWholeAndLocalViews
///
/// Initialize WholeModel, LocalModel and set data for diagrams
///

private void SetWholeAndLocalViews()
{
WholeModel = InitializeGraphLinksModel();
LocalModel = InitializeGraphLinksModel();
WholeModel = GraphLinksModel;
_view.myWholeView.Model = WholeModel;
_view.myLocalView.Model = LocalModel;
LocalModel.Modifiable = true;
_view.myWholeView.InitialLayoutCompleted += WholeViewInitialLayoutCompleted;
}
#endregion
#region WholeViewInitialLayoutCompleted
///
/// Initialize wholeview diagram
///

///
///
private void WholeViewInitialLayoutCompleted(object s, DiagramEventArgs e)
{
_view.myWholeView.InitialLayoutCompleted -= WholeViewInitialLayoutCompleted;
Node node = _view.myWholeView.Nodes.ElementAtOrDefault(1);
if (node != null)
node.IsSelected = true;
}
#endregion
#region Devices
///
/// Holds the data for the devices
///

private List<Device> _devices;
public List<Device> Devices
{
get
{
return _devices;
}
set
{
if (_devices == value)
return;
_devices = value;
RaisePropertyChanged(() => Devices);
}
}
#endregion

#region WholeModel and LocalModel

GraphLinksModel<Device, String, String, LinkData> WholeModel { get; set; }
GraphLinksModel<Device, String, String, LinkData> LocalModel { get; set; }
#endregion
#region InitializeGraphLinksModel
///


/// Initializes GraphLinksModel
///

///
private static GraphLinksModel<Device, String, String, LinkData> InitializeGraphLinksModel()
{
var model = new GraphLinksModel<Device, String, String, LinkData>
{
MemberNodesPath = String.Empty,
GroupNodePath = String.Empty
};
return model;
}
#endregion

///


/// Make sure a given node data is in the LocalModel along with all of the nodes and links
/// connected to it up to some number of links in distance
///

///
public void FocusOn(Device device)
{
Contract.Assert(device != null, “data is null.”);
CurrentDevice = device;
_view.deviceListBox.SelectedItem = CurrentDevice;
// Make sure it’s visible and selected in myWholeView
Node overviewnode = _view.myWholeView.PartManager.FindNodeForData(CurrentDevice, _view.myWholeView.Model);
if (overviewnode != null)
{
_view.myWholeView.Panel.MakeVisible(overviewnode, Rect.Empty);
_view.myWholeView.Select(overviewnode);
var highlight = _view.myWholeView.PartsModel.FindNodeByKey(“Highlight”);
if (highlight != null) highlight.Location = overviewnode.Location;
}
// find all connected node data and link data, and make sure there are Parts for them
LocalModel.StartTransaction(“add local graph”);
var wanted = new HashSet<Device>();
CollectLocals(CurrentDevice, null, 2, wanted);
// and remove all node and link data that are not connected to the focussed node data
foreach (var existing in LocalModel.NodesSource.OfType<Device>().ToList())
{
if (!wanted.Contains(existing)) LocalModel.RemoveNode(existing);
}
LocalModel.CommitTransaction(“add local graph”);//Do it in transaction
// center and select that Node
_view.myLocalView.Dispatcher.BeginInvoke(() =>
{
var localnode = _view.myLocalView.PartManager.FindNodeForData(CurrentDevice, _view.myLocalView.Model);
_view.myLocalView.Panel.CenterPart(localnode);
_view.myLocalView.Select(localnode);
});
}
#endregion

///


/// this collects connected node data up to LEVEL levels away, and adds the node link data to the model
///

///
///
///
///
private void CollectLocals(Device data, LinkData linkdata, int level, HashSet<Device> wanted)
{
if (data == null) return;
// stop recursing beyond the number of levels
if (level < 0) return;
// always add the link data (but it might be null, which is OK)
LocalModel.AddLink(linkdata);
// stop if we’ve already seen the node
if (wanted.Contains(data)) return;
// otherwise add it to our collection
wanted.Add(data);
LocalModel.AddNode(data);
// recurse through all connected nodes
foreach (var link in WholeModel.GetLinksForNode(data))
{
CollectLocals(WholeModel.GetFromNodeForLink(link), link, level - 1, wanted);
CollectLocals(WholeModel.GetToNodeForLink(link), link, level - 1, wanted);
}
}
} }
Here is the converter:
using System; using System.Diagnostics; using System.Globalization; using System.Windows; using System.Windows.Data; namespace SLDeviceDatacontract.Converters { public class HasChildrenVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null) throw new ArgumentNullException("value", "value is null."); Debug.Assert(value != null, "value is null."); var numberOfChildren = (int)value;

return numberOfChildren > 1 ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

}

What am I doing wrong?
Thank you in advance.

By default there’s no layout performed just because you make some nodes or links visible (or not).

To get that behavior, add the following attribute to your LayeredDigraphLayout (or any other layout):
ConditionFlags=“Standard VisibleChanged”

[If this were WPF, you would set the Conditions property, not ConditionFlags.]

Thank you Walter. I did set the property it works now, except when first loaded it looks as shown below. The Television node has child nodes but it is shown with minus button as if it was expanded and child nodes not shown.

It should be displayed as shown below:
And when clicked on Television node, it should be displayed as shown below:
What am I missing?

A number of the samples demonstrate how to make sure the appearance of the expander element is consistent with the actual state. Some data-bind the text to be either “+” or “-”, and some data-bind the visibility of arbitrary elements so that you can use any elements at all for either state within the expander “button”.