From 488670e4b67287515cfd632b2733bc775cf55e5a Mon Sep 17 00:00:00 2001 From: masarray Date: Tue, 21 Jul 2026 02:49:18 +0700 Subject: [PATCH 1/2] Show and copy exact fault-transfer diagnostics --- FaultRecordWindow.Diagnostics.cs | 116 ++++++++++++++++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/FaultRecordWindow.Diagnostics.cs b/FaultRecordWindow.Diagnostics.cs index 90ac632fe..b968c32a7 100644 --- a/FaultRecordWindow.Diagnostics.cs +++ b/FaultRecordWindow.Diagnostics.cs @@ -1,11 +1,18 @@ +using System.Collections.Specialized; +using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Data; +using System.Windows.Threading; namespace ArIED61850Tester; public partial class FaultRecordWindow { + private bool _diagnosticHooksInstalled; + private string _selectedTransferDiagnostic = + "No transfer failure has been recorded. Run a download, then select a failed row."; + static FaultRecordWindow() { EventManager.RegisterClassHandler( @@ -15,6 +22,12 @@ static FaultRecordWindow() handledEventsToo: true); } + public string SelectedTransferDiagnostic + { + get => _selectedTransferDiagnostic; + private set => Set(ref _selectedTransferDiagnostic, value ?? string.Empty); + } + private static void OnFaultRecordRowLoaded(object sender, RoutedEventArgs e) { if (sender is not DataGridRow row || @@ -34,4 +47,105 @@ private static void OnFaultRecordRowLoaded(object sender, RoutedEventArgs e) }); ToolTipService.SetShowDuration(row, 30_000); } -} + + private void Diagnostics_ContentRendered(object? sender, EventArgs e) + { + if (_diagnosticHooksInstalled) + return; + + _diagnosticHooksInstalled = true; + Records.CollectionChanged += DiagnosticRecords_CollectionChanged; + foreach (var row in Records) + AttachDiagnosticRow(row); + } + + private void DiagnosticRecords_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + { + foreach (var item in e.NewItems.OfType()) + AttachDiagnosticRow(item); + } + + if (e.OldItems != null) + { + foreach (var item in e.OldItems.OfType()) + item.PropertyChanged -= DiagnosticRow_PropertyChanged; + } + } + + private void AttachDiagnosticRow(FaultRecordRow row) + { + row.PropertyChanged -= DiagnosticRow_PropertyChanged; + row.PropertyChanged += DiagnosticRow_PropertyChanged; + } + + private void DiagnosticRow_PropertyChanged(object? sender, PropertyChangedEventArgs e) + { + if (sender is not FaultRecordRow row || + e.PropertyName != nameof(FaultRecordRow.Detail) || + string.IsNullOrWhiteSpace(row.Detail) || + !row.Status.Equals("Failed", StringComparison.OrdinalIgnoreCase)) + { + return; + } + + ShowTransferDiagnostic(row, expand: true); + } + + private void FaultRecordsGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (FaultRecordsGrid.SelectedItem is FaultRecordRow row && + !string.IsNullOrWhiteSpace(row.Detail)) + { + ShowTransferDiagnostic( + row, + expand: row.Status.Equals("Failed", StringComparison.OrdinalIgnoreCase)); + } + } + + private void ShowTransferDiagnostic(FaultRecordRow row, bool expand) + { + void Apply() + { + SelectedTransferDiagnostic = BuildVisibleDiagnostic(row); + if (!ReferenceEquals(FaultRecordsGrid.SelectedItem, row)) + FaultRecordsGrid.SelectedItem = row; + FaultRecordsGrid.ScrollIntoView(row); + if (expand) + TransferDiagnosticsExpander.IsExpanded = true; + } + + if (Dispatcher.CheckAccess()) + Apply(); + else + Dispatcher.BeginInvoke(DispatcherPriority.DataBind, new Action(Apply)); + } + + private string BuildVisibleDiagnostic(FaultRecordRow row) + => $"Device : {DeviceName}\r\n" + + $"Endpoint : {EndpointText}\r\n" + + $"Record : {row.RecordName}\r\n" + + $"Remote directory : {row.RemoteDirectory}\r\n" + + $"Files : {row.FilesText}\r\n" + + $"Status : {row.Status}\r\n" + + $"Captured local : {DateTimeOffset.Now:O}\r\n" + + new string('=', 76) + "\r\n" + + row.Detail.Trim(); + + private void CopyDiagnostic_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrWhiteSpace(SelectedTransferDiagnostic)) + return; + + try + { + Clipboard.SetText(SelectedTransferDiagnostic); + StatusText = "Transfer diagnostic copied to the clipboard."; + } + catch (Exception ex) + { + StatusText = $"Could not copy the transfer diagnostic: {ex.Message}"; + } + } +} \ No newline at end of file From 9ed725055259ba2026b3981b27cc28a9f5d50ab3 Mon Sep 17 00:00:00 2001 From: masarray Date: Tue, 21 Jul 2026 02:50:16 +0700 Subject: [PATCH 2/2] Add expandable transfer diagnostic panel --- FaultRecordWindow.xaml | 46 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/FaultRecordWindow.xaml b/FaultRecordWindow.xaml index d9a0afd2f..d01e0a3eb 100644 --- a/FaultRecordWindow.xaml +++ b/FaultRecordWindow.xaml @@ -2,11 +2,12 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="IEC 61850 Fault Records" - Width="1120" Height="720" MinWidth="900" MinHeight="560" + Width="1120" Height="760" MinWidth="900" MinHeight="600" WindowStartupLocation="CenterOwner" Background="#F4F7FB" FontFamily="Aptos, Segoe UI Variable Text, Segoe UI, Calibri" Loaded="Window_Loaded" + ContentRendered="Diagnostics_ContentRendered" Closed="Window_Closed">