Browse Source

Object graph - rewrote calculation of node size. Now arrows fit.

pull/15/head
mkonicek 15 years ago
parent
commit
fac118b615
  1. 28
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingObservableCollection.cs
  2. 6
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml
  3. 54
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs
  4. 11
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/PositionedNode.cs
  5. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs

28
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingObservableCollection.cs

@ -5,31 +5,33 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace Debugger.AddIn.Visualizers.Common namespace Debugger.AddIn.Visualizers.Common
{ {
/// <summary> /// <summary>
/// Wrapper of ObservableCollection&lt;IEvaluate&gt; /// Proxy wrapping ObservableCollection&lt;IEvaluate&gt;
/// with lazy indexer, suitable for Controls that use indexer to query for data as needed (eg. ListView). /// with lazy indexer, suitable for Controls that use indexer to query data as needed (eg. ListView).
/// </summary> /// </summary>
public class VirtualizingObservableCollection<T> : ObservableCollection<T>, IList<T>, IList public class VirtualizingObservableCollection<T> : ObservableCollection<T>, IList<T>, IList
{ {
ObservableCollection<T> lazifiedCollection; ObservableCollection<T> collection;
public VirtualizingObservableCollection(ObservableCollection<T> lazifiedCollection) public VirtualizingObservableCollection(ObservableCollection<T> collection)
{ {
this.lazifiedCollection = lazifiedCollection; this.collection = collection;
this.lazifiedCollection.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(lazifiedCollection_CollectionChanged); this.collection.CollectionChanged += UnderlyingCollection_Changed;
} }
void lazifiedCollection_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) void UnderlyingCollection_Changed(object sender, NotifyCollectionChangedEventArgs e)
{ {
// Notify when someone changes the underlying collection, so that UI always stays in sync
OnCollectionChanged(e); OnCollectionChanged(e);
} }
public new int Count public new int Count
{ {
get { return this.lazifiedCollection.Count; } get { return this.collection.Count; }
} }
/// <summary> /// <summary>
@ -39,16 +41,12 @@ namespace Debugger.AddIn.Visualizers.Common
{ {
get get
{ {
var underlyingItem = this.lazifiedCollection[index]; var underlyingItem = this.collection[index];
IEvaluate itemLazy = underlyingItem as IEvaluate; IEvaluate itemLazy = underlyingItem as IEvaluate;
if (itemLazy != null) if (itemLazy != null && (!itemLazy.IsEvaluated)) {
{
if (!itemLazy.IsEvaluated)
{
itemLazy.Evaluate(); itemLazy.Evaluate();
} }
} // return evaluated items
// return item, evaluated if it was IEvaluate
return underlyingItem; return underlyingItem;
} }
set set

6
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml

@ -18,7 +18,7 @@
<Border Background="#ddeeff" BorderThickness="1,1,1,0" BorderBrush="DarkGray" HorizontalAlignment="Stretch" Padding="1"> <Border Background="#ddeeff" BorderThickness="1,1,1,0" BorderBrush="DarkGray" HorizontalAlignment="Stretch" Padding="1">
<TextBlock>Hello</TextBlock> <TextBlock>Hello</TextBlock>
</Border> --> </Border> -->
<ListView Name="listView" ScrollViewer.VerticalScrollBarVisibility="Auto"> <ListView Name="listView" ScrollViewer.VerticalScrollBarVisibility="Auto" Width="200" Height="300">
<ListView.Background> <ListView.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1"> <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#ddeeff" Offset="0.0" /> <GradientStop Color="#ddeeff" Offset="0.0" />
@ -85,7 +85,7 @@
</GridViewColumn.CellTemplate> </GridViewColumn.CellTemplate>
</GridViewColumn> </GridViewColumn>
<!-- Name --> <!-- Name -->
<GridViewColumn Header="Name" Width="Auto"> <GridViewColumn Header="Name" Width="60">
<GridViewColumn.CellTemplate> <GridViewColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
@ -95,7 +95,7 @@
</GridViewColumn.CellTemplate> </GridViewColumn.CellTemplate>
</GridViewColumn> </GridViewColumn>
<!-- Text --> <!-- Text -->
<GridViewColumn Header="Value " Width="Auto" CellTemplate="{StaticResource valueColumnTemplate}"> <GridViewColumn Header="Value" Width="60" CellTemplate="{StaticResource valueColumnTemplate}">
</GridViewColumn> </GridViewColumn>
</GridView.Columns> </GridView.Columns>
</GridView> </GridView>

54
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs

@ -46,7 +46,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
// shown in the ListView // shown in the ListView
private ObservableCollection<ContentNode> view = new ObservableCollection<ContentNode>(); private ObservableCollection<ContentNode> items = new ObservableCollection<ContentNode>();
private ContentNode root; private ContentNode root;
/// <summary> /// <summary>
@ -55,19 +55,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
public ContentNode Root public ContentNode Root
{ {
get { return this.root; } get { return this.root; }
set set {
{
this.root = value; this.root = value;
this.view = getInitialView(this.root); this.items = GetInitialItems(this.root);
// data virtualization, ContentPropertyNode implements IEvaluate // data virtualization, ContentPropertyNode implements IEvaluate
this.listView.ItemsSource = new VirtualizingObservableCollection<ContentNode>(this.view); this.listView.ItemsSource = new VirtualizingObservableCollection<ContentNode>(this.items);
/*int maxLen = this.view.MaxOrDefault(contentNode => { return contentNode.Name.Length; }, 0);
int spaces = Math.Max((int)(maxLen * 1.8 - 3), 0);
string addedSpaces = StringHelper.Repeat(' ', spaces);
GridView gv = listView.View as GridView;
// hack - autosize Name column
gv.Columns[1].Header = "Name" + addedSpaces;*/
//AutoSizeColumns(); //AutoSizeColumns();
@ -108,14 +100,28 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
} }
} }
public PositionedGraphNodeControl() public void CalculateWidthHeight()
{ {
InitializeComponent(); int maxLen = this.items.MaxOrDefault(contentNode => contentNode.Name.Length, 0);
Init(); int spaces = Math.Max((int)(maxLen * 1.8 - 3), 0);
GridView gv = listView.View as GridView;
gv.Columns[1].Width = 50 + spaces * 2.5;
gv.Columns[2].Width = 80;
listView.Width = gv.Columns[0].Width + gv.Columns[1].Width + gv.Columns[2].Width + 10;
int maxItems = 10;
listView.Height = Math.Min(this.items.Count, maxItems) * 20;
if (this.items.Count > maxItems) {
listView.Width += 30; // for scrollbar
}
this.Width = listView.Width + 2;
this.Height = listView.Height + 2;
} }
public void Init() public PositionedGraphNodeControl()
{ {
InitializeComponent();
PropertyExpanded = null; PropertyExpanded = null;
PropertyCollapsed = null; PropertyCollapsed = null;
ContentNodeExpanded = null; ContentNodeExpanded = null;
@ -165,7 +171,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
{ {
var clickedButton = (ToggleButton)e.Source; var clickedButton = (ToggleButton)e.Source;
var clickedNode = (ContentNode)(clickedButton).DataContext; var clickedNode = (ContentNode)(clickedButton).DataContext;
int clickedIndex = this.view.IndexOf(clickedNode); int clickedIndex = this.items.IndexOf(clickedNode);
//clickedNode.IsExpanded = !clickedNode.IsExpanded; // done by data binding //clickedNode.IsExpanded = !clickedNode.IsExpanded; // done by data binding
clickedButton.Content = clickedNode.IsExpanded ? "-" : "+"; // could be done by a converter clickedButton.Content = clickedNode.IsExpanded ? "-" : "+"; // could be done by a converter
@ -175,7 +181,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
int i = 1; int i = 1;
foreach (var childNode in clickedNode.Children) foreach (var childNode in clickedNode.Children)
{ {
this.view.Insert(clickedIndex + i, childNode); this.items.Insert(clickedIndex + i, childNode);
i++; i++;
} }
// insertChildren(clickedNode, this.view, clickedIndex); // TODO // insertChildren(clickedNode, this.view, clickedIndex); // TODO
@ -184,14 +190,16 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
else else
{ {
// remove whole subtree // remove whole subtree
int size = subtreeSize(clickedNode) - 1; int size = SubtreeSize(clickedNode) - 1;
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
this.view.RemoveAt(clickedIndex + 1); this.items.RemoveAt(clickedIndex + 1);
} }
OnContentNodeCollapsed(clickedNode); OnContentNodeCollapsed(clickedNode);
} }
CalculateWidthHeight();
//AutoSizeColumns(); //AutoSizeColumns();
// set to Auto again to resize columns // set to Auto again to resize columns
@ -208,14 +216,14 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing
this.listView.Width = double.NaN;*/ this.listView.Width = double.NaN;*/
} }
private ObservableCollection<ContentNode> getInitialView(ContentNode root) ObservableCollection<ContentNode> GetInitialItems(ContentNode root)
{ {
return new ObservableCollection<ContentNode>(root.FlattenChildrenExpanded()); return new ObservableCollection<ContentNode>(root.FlattenChildrenExpanded());
} }
private int subtreeSize(ContentNode node) int SubtreeSize(ContentNode node)
{ {
return 1 + node.Children.Sum(child => (child.IsExpanded ? subtreeSize(child) : 1)); return 1 + node.Children.Sum(child => (child.IsExpanded ? SubtreeSize(child) : 1));
} }
#region event helpers #region event helpers

11
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/PositionedNode.cs

@ -90,11 +90,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
public double Top { get; set; } public double Top { get; set; }
public double Width public double Width
{ {
get { return NodeVisualControl.DesiredSize.Width; } get { return NodeVisualControl.Width; }
} }
public double Height public double Height
{ {
get { return NodeVisualControl.DesiredSize.Height; } get { return NodeVisualControl.Height; }
} }
public Point LeftTop public Point LeftTop
@ -142,5 +142,12 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
box = new SplineRouting.Box(this); box = new SplineRouting.Box(this);
return box.Inflated(padding); return box.Inflated(padding);
} }
public void MeasureVisualControl()
{
if ((this.NodeVisualControl != null)) {
this.NodeVisualControl.CalculateWidthHeight();
}
}
} }
} }

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/Tree/TreeLayout.cs

@ -52,6 +52,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
foreach (ObjectGraphNode objectNode in objectGraph.ReachableNodes) { foreach (ObjectGraphNode objectNode in objectGraph.ReachableNodes) {
var posNode = new PositionedNode(objectNode); var posNode = new PositionedNode(objectNode);
posNode.InitContentFromObjectNode(expanded); posNode.InitContentFromObjectNode(expanded);
posNode.MeasureVisualControl();
positionedGraph.AddNode(posNode); positionedGraph.AddNode(posNode);
positionedNodeFor[objectNode] = posNode; positionedNodeFor[objectNode] = posNode;
} }
@ -100,7 +101,6 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
} }
} }
} }
root.Measure();
root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize); root.SubtreeSize = Math.Max(GetLateralSizeWithMargin(root), subtreeSize);
} }

Loading…
Cancel
Save