diff --git a/TuneUp/TuneUpWindow.xaml b/TuneUp/TuneUpWindow.xaml
index 9622724..5d5ad4d 100644
--- a/TuneUp/TuneUpWindow.xaml
+++ b/TuneUp/TuneUpWindow.xaml
@@ -4,11 +4,19 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TuneUp"
+ xmlns:ui="clr-namespace:Dynamo.UI;assembly=DynamoCoreWpf"
xmlns:componentmodel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Width="500" Height="100">
-
+
+
+
+
+
+
+
+
@@ -27,11 +35,59 @@
+
+
-
@@ -185,12 +246,12 @@
-
@@ -200,7 +261,6 @@
-
diff --git a/TuneUp/TuneUpWindow.xaml.cs b/TuneUp/TuneUpWindow.xaml.cs
index fc096c9..1fd729e 100644
--- a/TuneUp/TuneUpWindow.xaml.cs
+++ b/TuneUp/TuneUpWindow.xaml.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
@@ -117,6 +118,34 @@ private void RecomputeGraph_Click(object sender, RoutedEventArgs e)
(NodeAnalysisTable.DataContext as TuneUpWindowViewModel).ResetProfiling();
}
+ ///
+ /// Handles the sorting event for the NodeAnalysisTable DataGrid.
+ /// Updates the SortingOrder property in the view model based on the column header clicked by the user.
+ ///
+ private void NodeAnalysisTable_Sorting(object sender, DataGridSortingEventArgs e)
+ {
+ var viewModel = NodeAnalysisTable.DataContext as TuneUpWindowViewModel;
+ if (viewModel != null)
+ {
+ viewModel.SortingOrder = e.Column.Header switch
+ {
+ "#" => "number",
+ "Name" => "name",
+ "Execution Time (ms)" => "time",
+ _ => viewModel.SortingOrder
+ };
+
+ // Set the sorting direction of the datagrid column
+ e.Column.SortDirection = viewModel.SortDirection == ListSortDirection.Descending
+ ? ListSortDirection.Descending
+ : ListSortDirection.Ascending;
+
+ // Apply custom sorting to ensure total times are at the bottom
+ viewModel.ApplySorting();
+ e.Handled = true;
+ }
+ }
+
private void ExportTimes_Click(object sender, RoutedEventArgs e)
{
(NodeAnalysisTable.DataContext as TuneUpWindowViewModel).ExportToCsv();
diff --git a/TuneUp/TuneUpWindowViewModel.cs b/TuneUp/TuneUpWindowViewModel.cs
index 42e17ca..5a4ace5 100644
--- a/TuneUp/TuneUpWindowViewModel.cs
+++ b/TuneUp/TuneUpWindowViewModel.cs
@@ -28,11 +28,17 @@ public enum ProfiledNodeState
[Display(Name = "Executed On Current Run")]
ExecutedOnCurrentRun = 1,
+ [Display(Name = "Executed On Current Run")]
+ ExecutedOnCurrentRunTotal = 2,
+
[Display(Name = "Executed On Previous Run")]
- ExecutedOnPreviousRun = 2,
+ ExecutedOnPreviousRun = 3,
+
+ [Display(Name = "Executed On Previous Run")]
+ ExecutedOnPreviousRunTotal = 4,
[Display(Name = "Not Executed")]
- NotExecuted = 3,
+ NotExecuted = 5,
}
///
@@ -52,6 +58,9 @@ public class TuneUpWindowViewModel : NotificationObject, IDisposable
private Dictionary nodeDictionary = new Dictionary();
private SynchronizationContext uiContext;
private bool isTuneUpChecked = false;
+ private ListSortDirection sortDirection;
+ private string sortingOrder;
+
///
/// Name of the row to display current execution time
@@ -96,10 +105,48 @@ private HomeWorkspaceModel CurrentWorkspace
}
}
}
+
+ ///
+ /// Gets or sets the sorting order and toggles the sort direction.
+ ///
+ public string SortingOrder
+ {
+ get => sortingOrder;
+ set
+ {
+ if (sortingOrder != value)
+ {
+ sortingOrder = value;
+ SortDirection = ListSortDirection.Ascending;
+ }
+ else
+ {
+ SortDirection = SortDirection == ListSortDirection.Ascending
+ ? ListSortDirection.Descending
+ : ListSortDirection.Ascending;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the sort direction and raises property change notification if the value changes.
+ ///
+ public ListSortDirection SortDirection
+ {
+ get => sortDirection;
+ set
+ {
+ if (sortDirection != value)
+ {
+ sortDirection = value;
+ }
+ }
+ }
+
#endregion
#region Public Properties
-
+
///
/// Is the recomputeAll button enabled in the UI. Users should not be able to force a
/// reset of the engine and re-execution of the graph if one is still ongoing. This causes...trouble.
@@ -294,14 +341,8 @@ private void CurrentWorkspaceModel_EvaluationCompleted(object sender, Dynamo.Mod
ProfiledNodesCollection.Dispatcher.Invoke(() =>
{
- ProfiledNodesCollection.SortDescriptions.Clear();
- // Sort nodes into execution group
- ProfiledNodesCollection.SortDescriptions.Add(new SortDescription(nameof(ProfiledNodeViewModel.State), ListSortDirection.Ascending));
-
- // Sort nodes into execution order and make sure Total execution time is always bottom
- ProfiledNodesCollection.SortDescriptions.Add(new SortDescription(nameof(ProfiledNodeViewModel.ExecutionOrderNumber), ListSortDirection.Descending));
- if (ProfiledNodesCollection.View != null)
- ProfiledNodesCollection.View.Refresh();
+ ApplySorting();
+ ProfiledNodesCollection.View.Refresh();
});
}
@@ -321,13 +362,33 @@ private void UpdateExecutionTime()
var totalSpanExecuted = new TimeSpan(ProfiledNodes.Where(n => n.WasExecutedOnLastRun).Sum(r => r.ExecutionTime.Ticks));
var totalSpanUnexecuted = new TimeSpan(ProfiledNodes.Where(n => !n.WasExecutedOnLastRun).Sum(r => r.ExecutionTime.Ticks));
ProfiledNodes.Add(new ProfiledNodeViewModel(
- CurrentExecutionString, totalSpanExecuted, ProfiledNodeState.ExecutedOnCurrentRun));
+ CurrentExecutionString, totalSpanExecuted, ProfiledNodeState.ExecutedOnCurrentRunTotal));
ProfiledNodes.Add(new ProfiledNodeViewModel(
- PreviousExecutionString, totalSpanUnexecuted, ProfiledNodeState.ExecutedOnPreviousRun));
+ PreviousExecutionString, totalSpanUnexecuted, ProfiledNodeState.ExecutedOnPreviousRunTotal));
}, null);
RaisePropertyChanged(nameof(TotalGraphExecutiontime));
}
+ ///
+ /// Applies the sorting logic to the ProfiledNodesCollection.
+ ///
+ public void ApplySorting()
+ {
+ ProfiledNodesCollection.SortDescriptions.Clear();
+
+ // Sort nodes into execution group
+ ProfiledNodesCollection.SortDescriptions.Add(new SortDescription(nameof(ProfiledNodeViewModel.State), ListSortDirection.Ascending));
+
+ // Sort nodes into execution order and make sure Total execution time is always bottom
+ var sortDescription = sortingOrder switch
+ {
+ "time" => new SortDescription(nameof(ProfiledNodeViewModel.ExecutionTime), sortDirection),
+ "name" => new SortDescription(nameof(ProfiledNodeViewModel.Name), sortDirection),
+ _ => new SortDescription(nameof(ProfiledNodeViewModel.ExecutionOrderNumber), sortDirection),
+ };
+ ProfiledNodesCollection.SortDescriptions.Add(sortDescription);
+ }
+
internal void OnNodeExecutionBegin(NodeModel nm)
{
var profiledNode = nodeDictionary[nm.GUID];