将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
<Window x:Class="XP.Common.GeneralForm.Views.RealTimeLogViewer"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
|
||||
xmlns:loc="clr-namespace:XP.Common.Localization.Extensions"
|
||||
Title="{loc:Localization LogViewer_Title}"
|
||||
Width="960" Height="600"
|
||||
MinWidth="700" MinHeight="400"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ShowInTaskbar="True"
|
||||
WindowStyle="SingleBorderWindow">
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<!-- 顶部工具栏 | Top toolbar -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 级别筛选栏 | Level filter bar -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 日志显示区 | Log display area -->
|
||||
<RowDefinition Height="*"/>
|
||||
<!-- 底部状态栏 | Bottom status bar -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- === 顶部工具栏 | Top Toolbar === -->
|
||||
<DockPanel Grid.Row="0" Margin="8,6" LastChildFill="True">
|
||||
<!-- 左侧:自动滚动开关 + 清空按钮 | Left: Auto-scroll toggle + Clear button -->
|
||||
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<telerik:RadToggleButton x:Name="AutoScrollToggle"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
IsChecked="{Binding IsAutoScroll, Mode=TwoWay}"
|
||||
Content="{loc:Localization LogViewer_AutoScroll}"
|
||||
Padding="10,4" Margin="0,0,6,0"/>
|
||||
<telerik:RadButton telerik:StyleManager.Theme="Crystal"
|
||||
Command="{Binding ClearCommand}"
|
||||
Content="{loc:Localization LogViewer_ClearLog}"
|
||||
Padding="10,4" Margin="0,0,12,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 右侧:过滤输入框 | Right: Filter input -->
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<TextBlock Text="{loc:Localization LogViewer_Filter}" VerticalAlignment="Center" Margin="0,0,4,0"/>
|
||||
<telerik:RadWatermarkTextBox telerik:StyleManager.Theme="Crystal"
|
||||
Text="{Binding FilterText, UpdateSourceTrigger=PropertyChanged, Delay=300}"
|
||||
WatermarkContent="{loc:Localization LogViewer_FilterWatermark}"
|
||||
Width="260" Padding="4,3"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<!-- === 级别筛选栏 | Level Filter Bar === -->
|
||||
<Border Grid.Row="1" Background="#FFF8F8F8" BorderBrush="#FFDDDDDD" BorderThickness="0,0,0,1" Padding="8,4">
|
||||
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||
<TextBlock Text="{loc:Localization LogViewer_LevelFilter}" VerticalAlignment="Center" Margin="0,0,8,0" Foreground="#FF666666" FontSize="12"/>
|
||||
<CheckBox Content="Debug" IsChecked="{Binding ShowDebug}" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="Gray"/>
|
||||
<CheckBox Content="Info" IsChecked="{Binding ShowInfo}" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="#FF1E1E1E"/>
|
||||
<CheckBox Content="Warning" IsChecked="{Binding ShowWarning}" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="#FFC88200"/>
|
||||
<CheckBox Content="Error" IsChecked="{Binding ShowError}" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="Red"/>
|
||||
<CheckBox Content="Fatal" IsChecked="{Binding ShowFatal}" VerticalAlignment="Center" Margin="0,0,10,0" Foreground="#FFB40000"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- === 日志显示区(RadGridView)| Log Display Area === -->
|
||||
<telerik:RadGridView Grid.Row="2"
|
||||
x:Name="LogGridView"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
ItemsSource="{Binding FilteredEntries}"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
RowIndicatorVisibility="Collapsed"
|
||||
ShowGroupPanel="False"
|
||||
ShowColumnHeaders="True"
|
||||
CanUserFreezeColumns="False"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
CanUserResizeColumns="True"
|
||||
IsFilteringAllowed="False"
|
||||
SelectionMode="Extended"
|
||||
FontFamily="Consolas"
|
||||
FontSize="12"
|
||||
Margin="4,0,4,0">
|
||||
<telerik:RadGridView.Columns>
|
||||
<!-- 时间戳列 | Timestamp column -->
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization LogViewer_ColTime}"
|
||||
DataMemberBinding="{Binding TimestampDisplay}"
|
||||
Width="100"
|
||||
IsReadOnly="True"/>
|
||||
|
||||
<!-- 级别列 | Level column -->
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization LogViewer_ColLevel}"
|
||||
DataMemberBinding="{Binding Level}"
|
||||
Width="60"
|
||||
IsReadOnly="True">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="{Binding LevelColor}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
|
||||
<!-- 来源列 | Source column -->
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization LogViewer_ColSource}"
|
||||
DataMemberBinding="{Binding Source}"
|
||||
Width="200"
|
||||
IsReadOnly="True">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="{Binding LevelColor}"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
|
||||
<!-- 消息列 | Message column -->
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization LogViewer_ColMessage}"
|
||||
DataMemberBinding="{Binding Message}"
|
||||
Width="*"
|
||||
IsReadOnly="True">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="{Binding LevelColor}"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
</telerik:RadGridView.Columns>
|
||||
</telerik:RadGridView>
|
||||
|
||||
<!-- === 底部状态栏 | Bottom Status Bar === -->
|
||||
<StatusBar Grid.Row="3" Background="#FFF0F0F0" BorderBrush="#FFCCCCCC" BorderThickness="0,1,0,0">
|
||||
<StatusBarItem>
|
||||
<TextBlock Text="{Binding StatusText}" Foreground="#FF666666" FontSize="12"/>
|
||||
</StatusBarItem>
|
||||
<Separator/>
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{loc:Localization LogViewer_MaxLines}" Foreground="#FF999999" FontSize="11" VerticalAlignment="Center"/>
|
||||
<telerik:RadNumericUpDown telerik:StyleManager.Theme="Crystal"
|
||||
Value="{Binding MaxLines, Mode=TwoWay}"
|
||||
Minimum="100" Maximum="10000"
|
||||
NumberDecimalDigits="0"
|
||||
SmallChange="500"
|
||||
Width="90" Height="22"
|
||||
VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Serilog.Events;
|
||||
using XP.Common.Logging.ViewModels;
|
||||
|
||||
namespace XP.Common.GeneralForm.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// 实时日志查看器窗口,订阅 Serilog 事件并实时显示
|
||||
/// Real-time log viewer window, subscribes to Serilog events and displays in real-time
|
||||
/// </summary>
|
||||
public partial class RealTimeLogViewer : Window
|
||||
{
|
||||
private readonly RealTimeLogViewerViewModel _viewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数 | Constructor
|
||||
/// </summary>
|
||||
/// <param name="maxLines">最大行数限制,默认 2000 | Max line count, default 2000</param>
|
||||
public RealTimeLogViewer(int maxLines = 2000)
|
||||
{
|
||||
_viewModel = new RealTimeLogViewerViewModel { MaxLines = maxLines };
|
||||
DataContext = _viewModel;
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
// 继承主窗口图标 | Inherit main window icon
|
||||
if (Application.Current?.MainWindow != null)
|
||||
{
|
||||
Icon = Application.Current.MainWindow.Icon;
|
||||
}
|
||||
|
||||
// 订阅自动滚动事件 | Subscribe to auto-scroll event
|
||||
_viewModel.ScrollToBottomRequested += OnScrollToBottomRequested;
|
||||
|
||||
// 加载缓冲区中的历史日志 | Load buffered history logs
|
||||
var history = RealTimeLogSink.Instance.GetBufferedHistory();
|
||||
foreach (var logEvent in history)
|
||||
{
|
||||
_viewModel.AddLogEvent(logEvent);
|
||||
}
|
||||
|
||||
// 订阅 Serilog Sink 事件(在历史加载之后,避免重复)| Subscribe after history load
|
||||
RealTimeLogSink.Instance.LogEventReceived += OnLogEventReceived;
|
||||
|
||||
Closed += OnWindowClosed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 接收 Serilog 日志事件 | Receive Serilog log event
|
||||
/// </summary>
|
||||
private void OnLogEventReceived(LogEvent logEvent)
|
||||
{
|
||||
_viewModel.AddLogEvent(logEvent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 自动滚动到底部 | Auto-scroll to bottom
|
||||
/// </summary>
|
||||
private void OnScrollToBottomRequested()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (LogGridView.Items.Count > 0)
|
||||
{
|
||||
var lastItem = LogGridView.Items[LogGridView.Items.Count - 1];
|
||||
LogGridView.ScrollIntoView(lastItem);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 滚动失败时静默处理 | Silently handle scroll failures
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭时取消订阅,防止内存泄漏 | Unsubscribe on close to prevent memory leaks
|
||||
/// </summary>
|
||||
private void OnWindowClosed(object? sender, EventArgs e)
|
||||
{
|
||||
_viewModel.ScrollToBottomRequested -= OnScrollToBottomRequested;
|
||||
RealTimeLogSink.Instance.LogEventReceived -= OnLogEventReceived;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user