Skip to content

Commit

Permalink
sort direction arrows + preserve order (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivaylo-matov authored Jul 16, 2024
1 parent ee93525 commit ce03050
Show file tree
Hide file tree
Showing 3 changed files with 184 additions and 34 deletions.
102 changes: 81 additions & 21 deletions TuneUp/TuneUpWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -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">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:SharedResourceDictionary Source="{x:Static ui:SharedDictionaryManager.DynamoColorsAndBrushesDictionaryUri}" />
<ui:SharedResourceDictionary Source="{x:Static ui:SharedDictionaryManager.DynamoModernDictionaryUri}" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid Name="MainGrid" >
<Grid.Resources>
<!-- DataGrid style -->
Expand All @@ -27,11 +35,59 @@
<Style x:Key="ColumnHeaderStyle1" TargetType="DataGridColumnHeader">
<Setter Property="Height" Value="20"/>
<Setter Property="Background" Value="#333333"/>
<Setter Property="Foreground" Value="#999999"/>
<Setter Property="FontSize" Value="10" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="{StaticResource MemberButtonText}"/>
<Setter Property="FontFamily" Value="{StaticResource ArtifaktElementRegular}"/>
<Setter Property="FontSize" Value="10"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderBrush" Value="#555555"/>
<Setter Property="Margin" Value="10,0,10,0"/>
<Setter Property="Margin" Value="5,0,10,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ContentPresenter x:Name="HeaderContent"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="11,0,0,0"/>
<Path x:Name="SortArrow"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
Grid.Column="0"
Margin="0,0,4,0"
Stretch="Fill"
Width="7" Height="6"
Fill="#999999"
VerticalAlignment="Center"
RenderTransformOrigin="0.5,0.5"
Visibility="Collapsed"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="SortDirection" Value="Ascending">
<Setter TargetName="HeaderContent" Property="Margin" Value="0"/>
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible"/>
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="180"/>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="SortDirection" Value="Descending">
<Setter TargetName="HeaderContent" Property="Margin" Value="0"/>
<Setter TargetName="SortArrow" Property="Visibility" Value="Visible"/>
<Setter TargetName="SortArrow" Property="RenderTransform">
<Setter.Value>
<RotateTransform Angle="0"/>
</Setter.Value>
</Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- DataGridRow style -->
<Style x:Key="RowStyle1" TargetType="DataGridRow">
Expand Down Expand Up @@ -70,6 +126,13 @@
</Setter.Value>
</Setter>
</Style>
<!-- TextBlock style for DataGrid columns -->
<Style x:Key="DataGridTextBlockStyle" TargetType="TextBlock">
<Setter Property="Foreground" Value="{StaticResource MemberButtonText}"/>
<Setter Property="FontFamily" Value="{StaticResource ArtifaktElementRegular}"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="10,0,10,0"/>
</Style>
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
Expand All @@ -82,7 +145,6 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<!-- Recompute All Button -->
<StackPanel
Orientation="Horizontal"
Expand All @@ -108,12 +170,12 @@
Click="ExportTimes_Click">
Export
</Button>
<Label Foreground="White">Total Graph Execution Time: </Label>
<Label Foreground="White"
<Label Foreground="{StaticResource NodeNameForeground}">Total Graph Execution Time:</Label>
<Label Foreground="{StaticResource NodeNameForeground}"
FontFamily="{StaticResource ArtifaktElementRegular}"
Name="TotalGraphExecutiontimeLabel"
Content="{Binding Path=TotalGraphExecutiontime, Mode=OneWay}"/>
</StackPanel>

<StackPanel Grid.Row="1">
<DataGrid
x:Name="NodeAnalysisTable"
Expand All @@ -122,7 +184,7 @@
Style="{StaticResource DataGridStyle1}"
AutoGenerateColumns="False"
CanUserAddRows="False"
Background="#353535"
Background="#353535"
FontSize="11"
VerticalAlignment="Center"
SelectionUnit="FullRow"
Expand All @@ -136,15 +198,15 @@
SelectionChanged="NodeAnalysisTable_SelectionChanged"
PreviewMouseDown="NodeAnalysisTable_PreviewMouseDown"
MouseLeave="NodeAnalysisTable_MouseLeave" >

<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock
Text="{Binding Name}"
Foreground="#ffffff"
Foreground="{StaticResource NodeNameForeground}"
FontFamily="{StaticResource ArtifaktElementRegular}"
Margin="3"
FontSize="12"
/>
Expand All @@ -153,15 +215,14 @@
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>

<DataGrid.Columns>

<!-- Execution Order -->
<DataGridTextColumn
Header="#"
Binding="{Binding Path=ExecutionOrderNumber}"
Foreground="#aaaaaa"
IsReadOnly="True"
Foreground="{StaticResource MemberButtonText}"
FontFamily="{StaticResource ArtifaktElementRegular}"
IsReadOnly="True"
Width="Auto">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
Expand All @@ -170,12 +231,12 @@
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

<!-- Node Name -->
<DataGridTextColumn
Header="Name"
Binding="{Binding Name}"
Foreground="#aaaaaa"
Foreground="{StaticResource MemberButtonText}"
FontFamily="{StaticResource ArtifaktElementRegular}"
IsReadOnly="True"
Width="*">
<DataGridTextColumn.ElementStyle>
Expand All @@ -185,12 +246,12 @@
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

<!-- Execution Time -->
<DataGridTextColumn
Header="Execution Time (ms)"
Binding="{Binding ExecutionMilliseconds}"
Foreground="#aaaaaa"
Foreground="{StaticResource MemberButtonText}"
FontFamily="{StaticResource ArtifaktElementRegular}"
IsReadOnly="True"
Width="Auto">
<DataGridTextColumn.ElementStyle>
Expand All @@ -200,7 +261,6 @@
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>

</DataGrid.Columns>
</DataGrid>
</StackPanel>
Expand Down
29 changes: 29 additions & 0 deletions TuneUp/TuneUpWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
Expand Down Expand Up @@ -117,6 +118,34 @@ private void RecomputeGraph_Click(object sender, RoutedEventArgs e)
(NodeAnalysisTable.DataContext as TuneUpWindowViewModel).ResetProfiling();
}

/// <summary>
/// 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.
/// </summary>
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();
Expand Down
87 changes: 74 additions & 13 deletions TuneUp/TuneUpWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}

/// <summary>
Expand All @@ -52,6 +58,9 @@ public class TuneUpWindowViewModel : NotificationObject, IDisposable
private Dictionary<Guid, ProfiledNodeViewModel> nodeDictionary = new Dictionary<Guid, ProfiledNodeViewModel>();
private SynchronizationContext uiContext;
private bool isTuneUpChecked = false;
private ListSortDirection sortDirection;
private string sortingOrder;


/// <summary>
/// Name of the row to display current execution time
Expand Down Expand Up @@ -96,10 +105,48 @@ private HomeWorkspaceModel CurrentWorkspace
}
}
}

/// <summary>
/// Gets or sets the sorting order and toggles the sort direction.
/// </summary>
public string SortingOrder
{
get => sortingOrder;
set
{
if (sortingOrder != value)
{
sortingOrder = value;
SortDirection = ListSortDirection.Ascending;
}
else
{
SortDirection = SortDirection == ListSortDirection.Ascending
? ListSortDirection.Descending
: ListSortDirection.Ascending;
}
}
}

/// <summary>
/// Gets or sets the sort direction and raises property change notification if the value changes.
/// </summary>
public ListSortDirection SortDirection
{
get => sortDirection;
set
{
if (sortDirection != value)
{
sortDirection = value;
}
}
}

#endregion

#region Public Properties

/// <summary>
/// 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.
Expand Down Expand Up @@ -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();
});
}

Expand All @@ -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));
}

/// <summary>
/// Applies the sorting logic to the ProfiledNodesCollection.
/// </summary>
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];
Expand Down

0 comments on commit ce03050

Please sign in to comment.