具备界面基础功能
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
<UserControl
|
||||
x:Class="SHH.CameraDashboard.ServiceNodesDiagnostic"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:SHH.CameraDashboard"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
|
||||
<local:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<local:InverseNullToVisibilityConverter x:Key="InverseNullToVisibilityConverter" />
|
||||
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid Background="{DynamicResource Brush.Bg.Window}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" MinWidth="250" />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="*" MinWidth="300" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListView
|
||||
x:Name="LogList"
|
||||
Grid.Column="0"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
ItemContainerStyle="{StaticResource Style.ListViewItem.Table}"
|
||||
ItemsSource="{Binding Logs}"
|
||||
SelectedItem="{Binding SelectedLog}">
|
||||
<ListView.View>
|
||||
<GridView ColumnHeaderContainerStyle="{StaticResource Style.GridViewHeader.Flat}">
|
||||
<GridViewColumn
|
||||
Width="150"
|
||||
DisplayMemberBinding="{Binding Time, StringFormat='MM-dd HH:mm:ss fff'}"
|
||||
Header="请求时间" />
|
||||
<GridViewColumn
|
||||
Width="60"
|
||||
DisplayMemberBinding="{Binding StatusCode}"
|
||||
Header="状态" />
|
||||
<GridViewColumn
|
||||
Width="70"
|
||||
DisplayMemberBinding="{Binding ElapsedMilliseconds}"
|
||||
Header="耗时 ms" />
|
||||
<GridViewColumn
|
||||
Width="60"
|
||||
DisplayMemberBinding="{Binding Method}"
|
||||
Header="动作" />
|
||||
<GridViewColumn
|
||||
Width="120"
|
||||
DisplayMemberBinding="{Binding AppModule}"
|
||||
Header="模块" />
|
||||
<GridViewColumn
|
||||
Width="300"
|
||||
DisplayMemberBinding="{Binding Url}"
|
||||
Header="URL" />
|
||||
</GridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
|
||||
<GridSplitter
|
||||
Grid.Column="1"
|
||||
Width="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{DynamicResource Brush.Bg.Panel}" />
|
||||
|
||||
<Grid Grid.Column="2" Background="{DynamicResource Brush.Bg.Input}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border
|
||||
Background="{DynamicResource Brush.Bg.Panel}"
|
||||
BorderBrush="{DynamicResource Brush.Border}"
|
||||
BorderThickness="0,0,0,1">
|
||||
<DockPanel LastChildFill="False">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<RadioButton
|
||||
Command="{Binding SwitchTabCommand}"
|
||||
CommandParameter="0"
|
||||
Content="Request"
|
||||
GroupName="Logs"
|
||||
IsChecked="True"
|
||||
Style="{StaticResource TabRadioStyle}" />
|
||||
<RadioButton
|
||||
Command="{Binding SwitchTabCommand}"
|
||||
CommandParameter="1"
|
||||
Content="Response"
|
||||
GroupName="Logs"
|
||||
Style="{StaticResource TabRadioStyle}" />
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
|
||||
<TextBox
|
||||
Grid.Row="1"
|
||||
IsReadOnly="True"
|
||||
Style="{StaticResource Style.TextBox.CodeEditor}"
|
||||
Text="{Binding DisplayContent}"
|
||||
Visibility="{Binding SelectedLog, Converter={StaticResource NullToVisibilityConverter}}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Visibility="{Binding SelectedLog, Converter={StaticResource InverseNullToVisibilityConverter}}">
|
||||
<TextBlock Foreground="{DynamicResource Brush.Text.Secondary}" Text="请选择一条日志查看详情" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<CheckBox
|
||||
Margin="15,0,0,0"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Top"
|
||||
Content="过滤自动发送"
|
||||
Foreground="{DynamicResource Brush.Text.Secondary}"
|
||||
IsChecked="{Binding IsFilterAutoLogs}"
|
||||
Style="{DynamicResource Style.CheckBox.Switch}" />
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace SHH.CameraDashboard
|
||||
{
|
||||
/// <summary>
|
||||
/// ServiceNodesDiagnostic.xaml 的交互逻辑
|
||||
/// </summary>
|
||||
public partial class ServiceNodesDiagnostic : UserControl
|
||||
{
|
||||
public ServiceNodesDiagnostic()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
126
SHH.CameraDashboard/Pages/Diagnostics/ServiceNodesViewModel.cs
Normal file
126
SHH.CameraDashboard/Pages/Diagnostics/ServiceNodesViewModel.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace SHH.CameraDashboard;
|
||||
|
||||
public class ServiceNodesViewModel : INotifyPropertyChanged, IOverlayClosable, IDisposable
|
||||
{
|
||||
// 接口要求的关闭事件
|
||||
public event Action? RequestClose;
|
||||
|
||||
// 日志数据集合
|
||||
public ObservableCollection<LogWebApiModel> Logs { get; } = new ObservableCollection<LogWebApiModel>();
|
||||
|
||||
private LogWebApiModel _selectedLog;
|
||||
public LogWebApiModel SelectedLog
|
||||
{
|
||||
get => _selectedLog;
|
||||
set
|
||||
{
|
||||
_selectedLog = value;
|
||||
OnPropertyChanged();
|
||||
UpdateDisplayContent(); // 选中项改变时更新右侧文本
|
||||
}
|
||||
}
|
||||
|
||||
private string _displayContent;
|
||||
public string DisplayContent
|
||||
{
|
||||
get => _displayContent;
|
||||
set { _displayContent = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
private int _currentTabIndex = 0; // 0: Request, 1: Response
|
||||
// =========================================================
|
||||
// [新增] 1. 过滤开关属性 (绑定到界面 CheckBox)
|
||||
// =========================================================
|
||||
private bool _isFilterAutoLogs;
|
||||
public bool IsFilterAutoLogs
|
||||
{
|
||||
get => _isFilterAutoLogs;
|
||||
set
|
||||
{
|
||||
_isFilterAutoLogs = value;
|
||||
OnPropertyChanged();
|
||||
// 可选:切换时是否要清空现有日志?根据需求决定
|
||||
// if (value) Logs.Clear();
|
||||
}
|
||||
}
|
||||
public ICommand ClearCommand { get; }
|
||||
public ICommand CloseCommand { get; }
|
||||
public ICommand SwitchTabCommand { get; }
|
||||
|
||||
public ServiceNodesViewModel()
|
||||
{
|
||||
// 【关键步骤】订阅全局 API 服务的日志事件
|
||||
WebApiService.Instance.OnRequestCompleted += OnNewLogReceived;
|
||||
|
||||
// 初始化指令
|
||||
ClearCommand = new RelayCommand<object>(_ => Logs.Clear());
|
||||
CloseCommand = new RelayCommand<object>(_ => RequestClose?.Invoke());
|
||||
|
||||
SwitchTabCommand = new RelayCommand<string>(index =>
|
||||
{
|
||||
_currentTabIndex = int.Parse(index);
|
||||
UpdateDisplayContent();
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// 当 WebApiService 产生新日志时的回调
|
||||
/// </summary>
|
||||
private void OnNewLogReceived(LogWebApiModel log)
|
||||
{
|
||||
// 检查程序是否正在退出
|
||||
if (Application.Current == null) return;
|
||||
|
||||
if (IsFilterAutoLogs && CheckIsAutoLog(log))
|
||||
{
|
||||
return; // 如果是自动日志且开启了过滤,直接丢弃,不进入 UI 线程
|
||||
}
|
||||
|
||||
// 【线程安全】必须将操作封送回 UI 线程
|
||||
Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
// 1. 将最新日志插入顶部
|
||||
Logs.Insert(0, log);
|
||||
|
||||
// 2. 限制日志数量 (例如只保留最近 500 条),防止内存溢出
|
||||
if (Logs.Count > 500)
|
||||
{
|
||||
Logs.RemoveAt(Logs.Count - 1);
|
||||
}
|
||||
|
||||
// 3. (可选) 如果你想让列表自动滚动,可以在 View 的 CodeBehind 里做,或者在这里处理选中项逻辑
|
||||
}, DispatcherPriority.Background);
|
||||
}
|
||||
private bool CheckIsAutoLog(LogWebApiModel log)
|
||||
{
|
||||
if (log.IsAutoPost) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void UpdateDisplayContent()
|
||||
{
|
||||
if (SelectedLog == null)
|
||||
{
|
||||
DisplayContent = string.Empty;
|
||||
return;
|
||||
}
|
||||
// 根据当前选中的 Tab 显示请求或响应内容
|
||||
DisplayContent = _currentTabIndex == 0 ? SelectedLog.RequestData : SelectedLog.ResponseData;
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
protected void OnPropertyChanged([CallerMemberName] string name = null)
|
||||
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
WebApiService.Instance.OnRequestCompleted -= OnNewLogReceived;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user