Skip to content

Commit 8bde6fd

Browse files
Merge pull request #913 from erikdarlingdata/feature/lite-dashboard-finops-splits
Split FinOps services and content code-behinds into partial classes
2 parents 95fc881 + 5025718 commit 8bde6fd

45 files changed

Lines changed: 11365 additions & 10357 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dashboard/App.xaml.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,16 @@ protected override void OnExit(ExitEventArgs e)
8989
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
9090
{
9191
var exception = e.ExceptionObject as Exception;
92+
93+
/* Silently swallow Hardcodet TrayToolTip race condition (issue #422) when it
94+
escapes the Dispatcher path — happens during tray-Exit shutdown when the
95+
Dispatcher's exception hooks are torn down before the tray library finishes. */
96+
if (exception != null && IsTrayToolTipCrash(exception))
97+
{
98+
Logger.Warning("Suppressed Hardcodet TrayToolTip crash (issue #422) in AppDomain handler");
99+
return;
100+
}
101+
92102
Logger.Fatal("Unhandled AppDomain Exception", exception ?? new Exception("Unknown exception"));
93103

94104
if (e.IsTerminating)
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (c) 2026 Erik Darling, Darling Data LLC
3+
*
4+
* This file is part of the SQL Server Performance Monitor.
5+
*
6+
* Licensed under the MIT License. See LICENSE file in the project root for full license information.
7+
*/
8+
9+
using System;
10+
using System.Collections.Generic;
11+
using System.Globalization;
12+
using System.IO;
13+
using System.Linq;
14+
using System.Text;
15+
using System.Threading.Tasks;
16+
using System.Windows;
17+
using System.Windows.Controls;
18+
using System.Windows.Controls.Primitives;
19+
using System.Windows.Data;
20+
using Microsoft.Win32;
21+
using PerformanceMonitorDashboard.Helpers;
22+
using PerformanceMonitorDashboard.Models;
23+
using PerformanceMonitorDashboard.Services;
24+
25+
namespace PerformanceMonitorDashboard.Controls
26+
{
27+
public partial class MemoryContent : UserControl
28+
{
29+
#region Context Menu Handlers
30+
31+
private void CopyCell_Click(object sender, RoutedEventArgs e)
32+
{
33+
if (sender is MenuItem menuItem && menuItem.Parent is ContextMenu contextMenu)
34+
{
35+
var dataGrid = TabHelpers.FindDataGridFromContextMenu(contextMenu);
36+
if (dataGrid != null && dataGrid.CurrentCell.Item != null)
37+
{
38+
var cellContent = TabHelpers.GetCellContent(dataGrid, dataGrid.CurrentCell);
39+
if (!string.IsNullOrEmpty(cellContent))
40+
{
41+
/* Use SetDataObject with copy=false to avoid WPF's problematic Clipboard.Flush() */
42+
Clipboard.SetDataObject(cellContent, false);
43+
}
44+
}
45+
}
46+
}
47+
48+
private void CopyRow_Click(object sender, RoutedEventArgs e)
49+
{
50+
if (sender is MenuItem menuItem && menuItem.Parent is ContextMenu contextMenu)
51+
{
52+
var dataGrid = TabHelpers.FindDataGridFromContextMenu(contextMenu);
53+
if (dataGrid != null && dataGrid.SelectedItem != null)
54+
{
55+
var rowText = TabHelpers.GetRowAsText(dataGrid, dataGrid.SelectedItem);
56+
/* Use SetDataObject with copy=false to avoid WPF's problematic Clipboard.Flush() */
57+
Clipboard.SetDataObject(rowText, false);
58+
}
59+
}
60+
}
61+
62+
private void CopyAllRows_Click(object sender, RoutedEventArgs e)
63+
{
64+
if (sender is MenuItem menuItem && menuItem.Parent is ContextMenu contextMenu)
65+
{
66+
var dataGrid = TabHelpers.FindDataGridFromContextMenu(contextMenu);
67+
if (dataGrid != null && dataGrid.Items.Count > 0)
68+
{
69+
var sb = new StringBuilder();
70+
71+
// Add headers
72+
var headers = new List<string>();
73+
foreach (var column in dataGrid.Columns)
74+
{
75+
if (column is DataGridBoundColumn)
76+
{
77+
headers.Add(Helpers.DataGridClipboardBehavior.GetHeaderText(column));
78+
}
79+
}
80+
sb.AppendLine(string.Join("\t", headers));
81+
82+
// Add all rows
83+
foreach (var item in dataGrid.Items)
84+
{
85+
sb.AppendLine(TabHelpers.GetRowAsText(dataGrid, item));
86+
}
87+
88+
/* Use SetDataObject with copy=false to avoid WPF's problematic Clipboard.Flush() */
89+
Clipboard.SetDataObject(sb.ToString(), false);
90+
}
91+
}
92+
}
93+
94+
private void ExportToCsv_Click(object sender, RoutedEventArgs e)
95+
{
96+
if (sender is MenuItem menuItem && menuItem.Parent is ContextMenu contextMenu)
97+
{
98+
var dataGrid = TabHelpers.FindDataGridFromContextMenu(contextMenu);
99+
if (dataGrid != null && dataGrid.Items.Count > 0)
100+
{
101+
string prefix = "memory";
102+
103+
104+
var saveFileDialog = new SaveFileDialog
105+
{
106+
FileName = $"{prefix}_{DateTime.Now:yyyyMMdd_HHmmss}.csv",
107+
DefaultExt = ".csv",
108+
Filter = "CSV Files (*.csv)|*.csv|All Files (*.*)|*.*"
109+
};
110+
111+
if (saveFileDialog.ShowDialog() == true)
112+
{
113+
try
114+
{
115+
var sb = new StringBuilder();
116+
117+
// Add headers
118+
var headers = new List<string>();
119+
foreach (var column in dataGrid.Columns)
120+
{
121+
if (column is DataGridBoundColumn)
122+
{
123+
headers.Add(TabHelpers.EscapeCsvField(Helpers.DataGridClipboardBehavior.GetHeaderText(column), TabHelpers.CsvSeparator));
124+
}
125+
}
126+
sb.AppendLine(string.Join(TabHelpers.CsvSeparator, headers));
127+
128+
// Add all rows
129+
foreach (var item in dataGrid.Items)
130+
{
131+
var values = TabHelpers.GetRowValues(dataGrid, item);
132+
sb.AppendLine(string.Join(TabHelpers.CsvSeparator, values.Select(v => TabHelpers.EscapeCsvField(v, TabHelpers.CsvSeparator))));
133+
}
134+
135+
File.WriteAllText(saveFileDialog.FileName, sb.ToString());
136+
MessageBox.Show($"Data exported successfully to:\n{saveFileDialog.FileName}", "Export Complete", MessageBoxButton.OK, MessageBoxImage.Information);
137+
}
138+
catch (Exception ex)
139+
{
140+
MessageBox.Show($"Error exporting data:\n\n{ex.Message}", "Export Error", MessageBoxButton.OK, MessageBoxImage.Error);
141+
}
142+
}
143+
}
144+
}
145+
}
146+
147+
#endregion
148+
}
149+
}

0 commit comments

Comments
 (0)