Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DYN-2475] Icons for sorting on datagrid headers #48

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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