From 0c8663d53a7cf64727a5d7edde8ab8f2a240a890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kon=C3=AD=C4=8Dek?= Date: Tue, 30 Jun 2009 07:18:11 +0000 Subject: [PATCH] Implemented PositionedGraphNodeControl, displaying tree of properties instead of flat list. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4371 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Drawing/PositionedGraphNodeControl.xaml | 96 ++++++++++++- .../PositionedGraphNodeControl.xaml.cs | 136 +++++++++++++++++- .../Graph/Layout/NestedNodeViewModel.cs | 30 +++- .../Graph/Layout/PositionedGraphNode.cs | 12 +- .../Graph/Layout/PositionedNodeProperty.cs | 1 + .../Graph/Layout/PropertyNodeViewModel.cs | 11 ++ .../Graph/VisualizerWPFWindow.xaml.cs | 4 +- 7 files changed, 269 insertions(+), 21 deletions(-) diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml index de437a9a6f..1f0b0cded2 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml @@ -1,7 +1,95 @@ - - - + xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" + xmlns:aero="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" + > + + + + + + + + + + + + + + + + + + + + + + + + + + + +p + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs index 7bb6f59a92..a74ca7baaf 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Drawing/PositionedGraphNodeControl.xaml.cs @@ -4,16 +4,20 @@ // // $Revision$ // -using Debugger.AddIn.Visualizers.Graph.Layout; -using System; -using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; +using Debugger.AddIn.Visualizers.Graph.Layout; +using System; +using System.Collections.Generic; +using System.Linq; +using Debugger.AddIn.Visualizers.Common; namespace Debugger.AddIn.Visualizers.Graph.Drawing { @@ -22,7 +26,6 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing /// public partial class PositionedGraphNodeControl : UserControl { - /* /// /// Occurs when a is expanded. /// @@ -31,11 +34,134 @@ namespace Debugger.AddIn.Visualizers.Graph.Drawing /// Occurs when a is collaped. /// public event EventHandler PropertyCollapsed; - */ + + + // shown in the ListView + private ObservableCollection view = new ObservableCollection(); + + private NestedNodeViewModel root; + /// + /// The tree to be displayed in this Control. + /// + public NestedNodeViewModel Root + { + get { return this.root; } + set + { + this.root = value; + this.view = initializeView(this.root); + // data virtualization, PropertyNodeViewModel implements IEvaluate + this.listView.ItemsSource = new VirtualizingObservableCollection(this.view); + //listView.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(listView_ScrollChanged)); + } + } public PositionedGraphNodeControl() { InitializeComponent(); } + + private void PropertyExpandButton_Click(object sender, RoutedEventArgs e) + { + var clickedButton = (ToggleButton)e.Source; + PropertyNodeViewModel clickedNode = null; + try + { + clickedNode = (PropertyNodeViewModel)(clickedButton).DataContext; + } + catch(InvalidCastException) + { + throw new InvalidOperationException("Clicked property expand button, button shouln't be there - DataContext is not PropertyNodeViewModel."); + } + + PositionedNodeProperty property = clickedNode.Property; + property.IsExpanded = !property.IsExpanded; + clickedButton.Content = property.IsExpanded ? "-p" : "+p"; + if (property.IsExpanded) + { + OnPropertyExpanded(property); + } + else + { + OnPropertyCollapsed(property); + } + } + + private void NestedExpandButton_Click(object sender, RoutedEventArgs e) + { + var clickedButton = (ToggleButton)e.Source; + var clickedNode = (NestedNodeViewModel)(clickedButton).DataContext; + int clickedIndex = this.view.IndexOf(clickedNode); + //clickedNode.IsExpanded = !clickedNode.IsExpanded; // done by data binding + clickedButton.Content = clickedNode.IsExpanded ? "-" : "+"; // could be done by a converter + + if (clickedNode.IsExpanded) + { + // insert children + int i = 1; + foreach (var childNode in clickedNode.Children) + { + this.view.Insert(clickedIndex + i, childNode); + i++; + } + } + else + { + // remove whole subtree + int size = subtreeSize(clickedNode) - 1; + for (int i = 0; i < size; i++) + { + this.view.RemoveAt(clickedIndex + 1); + } + } + + var a = new ListViewItem(); + + // set to Auto again to resize columns + var colName = (this.listView.View as GridView).Columns[0]; + var colValue = (this.listView.View as GridView).Columns[1]; + colName.Width = 300; + colName.Width = double.NaN; + colValue.Width = 300; + colValue.Width = double.NaN; + this.view.Insert(0, new NestedNodeViewModel()); + this.view.RemoveAt(0); + this.listView.UpdateLayout(); + this.listView.Width = colName.ActualWidth + colValue.ActualWidth + 30; + this.listView.Width = double.NaN; + } + + private ObservableCollection initializeView(NestedNodeViewModel root) + { + var view = new ObservableCollection(); + foreach (var topLevelNode in root.Children) + { + view.Add(topLevelNode); + } + return view; + } + + private int subtreeSize(NestedNodeViewModel node) + { + return 1 + node.Children.Sum(child => (child.IsExpanded ? subtreeSize(child) : 1)); + } + + #region event helpers + protected virtual void OnPropertyExpanded(PositionedNodeProperty property) + { + if (this.PropertyExpanded != null) + { + this.PropertyExpanded(this, new PositionedPropertyEventArgs(property)); + } + } + + protected virtual void OnPropertyCollapsed(PositionedNodeProperty property) + { + if (this.PropertyCollapsed != null) + { + this.PropertyCollapsed(this, new PositionedPropertyEventArgs(property)); + } + } + #endregion } } \ No newline at end of file diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/NestedNodeViewModel.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/NestedNodeViewModel.cs index b90fa126d1..83b91f55f7 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/NestedNodeViewModel.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/NestedNodeViewModel.cs @@ -16,6 +16,9 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout { public string Name { get; set; } public string Text { get; set; } + + private List children = new List(); + public List Children { get { return this.children; } } /// /// Is this expandable node? @@ -24,14 +27,33 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout /// /// Does this node have any children? /// - public bool HasChildren { get; set; } + public bool HasChildren { get { return this.Children.Count > 0; } } + + /// + /// Show a button to expand property associated with this node? + /// + public bool ShowExpandPropertyButton + { + get + { + var thisAsPropertyNode = this as PropertyNodeViewModel; + if (thisAsPropertyNode == null) + { + // this is NestedNodeViewModel -> no property, don't show expand button + return false; + } + else + { + // this is PositionedNodeViewModel -> show expand button when appropriate + PositionedNodeProperty property = thisAsPropertyNode.Property; + return (!property.IsAtomic && !property.IsNull); + } + } + } // if we bound this ViewModel to a TreeView, this would not be needed, // it is added "artificially", to support PositionedGraphNodeControl public bool IsExpanded { get; set; } - - private List children = new List(); - public List Children { get { return this.children; } } public NestedNodeViewModel() { diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraphNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraphNode.cs index c1e13e6e5c..42c3fb91b3 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraphNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedGraphNode.cs @@ -25,8 +25,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout get { return objectNode; } } - public event EventHandler Expanded; - public event EventHandler Collapsed; + public event EventHandler PropertyExpanded; + public event EventHandler PropertyCollapsed; private List properties = new List(); public List Properties @@ -127,17 +127,17 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout #region event helpers protected virtual void OnPropertyExpanded(object sender, PositionedPropertyEventArgs propertyArgs) { - if (this.Expanded != null) + if (this.PropertyExpanded != null) { - this.Expanded(sender, propertyArgs); + this.PropertyExpanded(sender, propertyArgs); } } protected virtual void OnPropertyCollapsed(object sender, PositionedPropertyEventArgs propertyArgs) { - if (this.Collapsed != null) + if (this.PropertyCollapsed != null) { - this.Collapsed(sender, propertyArgs); + this.PropertyCollapsed(sender, propertyArgs); } } #endregion diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs index 0a9a4b5a04..6a67de541e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNodeProperty.cs @@ -10,6 +10,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout { /// /// with outgoing . + /// Implements evaluation of value on demand using IEvaluate. /// public class PositionedNodeProperty : IEvaluate { diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PropertyNodeViewModel.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PropertyNodeViewModel.cs index f4a381c6bd..5c3cd308f3 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PropertyNodeViewModel.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PropertyNodeViewModel.cs @@ -17,9 +17,20 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout public PropertyNodeViewModel(PositionedNodeProperty positionedNodeProperty) { + if (positionedNodeProperty == null) + throw new ArgumentNullException("positionedNodeProperty"); + this.positionedProperty = positionedNodeProperty; } + /// + /// The PositionedNodeProperty this node contains. + /// + public PositionedNodeProperty Property + { + get { return this.positionedProperty; } + } + public bool IsEvaluated { get { return this.positionedProperty.IsEvaluated; } diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs index 02ff91c86f..f16407e477 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/VisualizerWPFWindow.xaml.cs @@ -141,8 +141,8 @@ namespace Debugger.AddIn.Visualizers.Graph { foreach (var node in posGraph.Nodes) { - node.Expanded += new EventHandler(node_Expanded); - node.Collapsed += new EventHandler(node_Collapsed); + node.PropertyExpanded += new EventHandler(node_Expanded); + node.PropertyCollapsed += new EventHandler(node_Collapsed); } }