将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<Window x:Class="XP.Hardware.PLC.Views.PlcAddrConfigEditorWindow"
|
||||
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;assembly=XP.Common"
|
||||
Title="{loc:Localization PlcAddrEditor_Title}"
|
||||
Width="1050" Height="750"
|
||||
MinWidth="950" MinHeight="650"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#FFF5F5F5">
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部:文件路径和操作按钮 | Top: File path and action buttons -->
|
||||
<Grid Grid.Row="0" Margin="0,0,0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="{loc:Localization PlcAddrEditor_FilePath}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,5,0"/>
|
||||
<TextBlock Grid.Column="1" Text="{Binding XmlFilePath}" VerticalAlignment="Center" Foreground="#FF666666" TextTrimming="CharacterEllipsis" Margin="0,0,10,0"/>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal">
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_Reload}" Command="{Binding ReloadCommand}" Width="70" Margin="0,0,5,0" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_Save}" Command="{Binding SaveCommand}" Width="70" Margin="0,0,5,0" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_Cancel}" Command="{Binding CancelCommand}" Width="70" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<!-- PLC 连接参数配置(已移除 WriteDbBlock)| PLC Connection Parameters (WriteDbBlock removed) -->
|
||||
<GroupBox Grid.Row="1" Header="{loc:Localization PlcAddrEditor_PlcConfigGroup}" Foreground="#FF333333" Margin="0,0,0,5"
|
||||
BorderBrush="#FFBDBDBD" Background="#FFFFFFFF">
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="8"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="8"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Row 1: IP, Port, Rack, Slot, PlcType -->
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="IP:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="0" Grid.Column="1" Text="{Binding IpAddress, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="3" Text="{loc:Localization PlcAddrEditor_Port}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="0" Grid.Column="4" Text="{Binding Port, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="6" Text="{loc:Localization PlcAddrEditor_Rack}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="0" Grid.Column="7" Text="{Binding Rack, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="9" Text="{loc:Localization PlcAddrEditor_Slot}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="0" Grid.Column="10" Text="{Binding Slot, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="0" Grid.Column="12" Text="{loc:Localization PlcAddrEditor_PlcType}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadComboBox Grid.Row="0" Grid.Column="13" ItemsSource="{Binding PlcTypes}" SelectedItem="{Binding SelectedPlcType}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
|
||||
<!-- Row 2: ReadDB, ReadStart, ReadLen, BulkReadInterval(已移除 WriteDB)| ReadDB, ReadStart, ReadLen, BulkReadInterval (WriteDB removed) -->
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="{loc:Localization PlcAddrEditor_ReadDB}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="2" Grid.Column="1" Text="{Binding ReadDbBlock, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="3" Text="{loc:Localization PlcAddrEditor_ReadStart}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="2" Grid.Column="4" Text="{Binding ReadStartAddress, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="6" Text="{loc:Localization PlcAddrEditor_ReadLen}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="2" Grid.Column="7" Text="{Binding ReadLength, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="2" Grid.Column="9" Text="{loc:Localization PlcAddrEditor_BulkReadInterval}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="2" Grid.Column="10" Text="{Binding BulkReadIntervalMs, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
|
||||
<!-- Row 3: ConnTimeout, ReadTimeout, WriteTimeout, Reconnect -->
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="{loc:Localization PlcAddrEditor_ConnTimeout}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="4" Grid.Column="1" Text="{Binding ConnectTimeoutMs, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="3" Text="{loc:Localization PlcAddrEditor_ReadTimeout}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="4" Grid.Column="4" Text="{Binding ReadTimeoutMs, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="6" Text="{loc:Localization PlcAddrEditor_WriteTimeout}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadWatermarkTextBox Grid.Row="4" Grid.Column="7" Text="{Binding WriteTimeoutMs, UpdateSourceTrigger=PropertyChanged}" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
<TextBlock Grid.Row="4" Grid.Column="9" Text="{loc:Localization PlcAddrEditor_Reconnect}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,2,0"/>
|
||||
<telerik:RadToggleSwitchButton Grid.Row="4" Grid.Column="10" IsChecked="{Binding BReConnect}" VerticalAlignment="Center" telerik:StyleManager.Theme="Crystal"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 信号地址定义表(动态 Group Tab 页)| Signal Address Definition Tables (Dynamic Group Tabs) -->
|
||||
<DockPanel Grid.Row="2">
|
||||
<!-- 工具栏:Group 增删 + 分隔 + 信号增删,同一行 | Toolbar: Group add/delete + separator + signal add/delete in one row -->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,5">
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_AddGroup}" Command="{Binding AddGroupCommand}" Width="100" Height="26" Margin="0,0,5,0" telerik:StyleManager.Theme="Crystal"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_DeleteGroup}" Command="{Binding DeleteGroupCommand}" Width="100" Height="26" Margin="0,0,5,0" telerik:StyleManager.Theme="Crystal"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_RenameGroup}" Command="{Binding RenameGroupCommand}" Width="110" Height="26" Margin="0,0,5,0" telerik:StyleManager.Theme="Crystal"/>
|
||||
<!-- 竖线分隔符 | Vertical separator -->
|
||||
<Separator Style="{StaticResource {x:Static ToolBar.SeparatorStyleKey}}" Width="1" Margin="5,2,10,2"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_AddSignal}" Command="{Binding AddSignalCommand}" Width="100" Height="26" Margin="0,0,5,0" telerik:StyleManager.Theme="Crystal"/>
|
||||
<telerik:RadButton Content="{loc:Localization PlcAddrEditor_DeleteSelectedSignal}" Command="{Binding DeleteSignalCommand}" Width="100" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 动态 Tab 页,绑定到 Groups 集合 | Dynamic tabs bound to Groups collection -->
|
||||
<telerik:RadTabControl ItemsSource="{Binding Groups}"
|
||||
SelectedItem="{Binding SelectedGroup}"
|
||||
telerik:StyleManager.Theme="Crystal">
|
||||
<!-- Tab 标题模板:显示 Group ID | Tab header template: display Group ID -->
|
||||
<telerik:RadTabControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding GroupId}"/>
|
||||
</DataTemplate>
|
||||
</telerik:RadTabControl.ItemTemplate>
|
||||
|
||||
<!-- Tab 内容模板:DBNumber 编辑 + 信号列表 | Tab content template: DBNumber edit + signal list -->
|
||||
<telerik:RadTabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<DockPanel Margin="5">
|
||||
<!-- 顶部:DBNumber 编辑字段 | Top: DBNumber edit field -->
|
||||
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,5">
|
||||
<TextBlock Text="{loc:Localization PlcAddrEditor_DbNumber}" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,5,0"/>
|
||||
<telerik:RadWatermarkTextBox Text="{Binding DBNumber, UpdateSourceTrigger=PropertyChanged}" Width="100" Height="26" telerik:StyleManager.Theme="Crystal"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- 信号列表 RadGridView | Signal list RadGridView -->
|
||||
<telerik:RadGridView x:Name="SignalGrid" ItemsSource="{Binding Signals}" AutoGenerateColumns="False"
|
||||
CanUserInsertRows="False" CanUserDeleteRows="False" SelectionMode="Single"
|
||||
SelectedItem="{Binding DataContext.SelectedSignal, RelativeSource={RelativeSource AncestorType=Window}, Mode=TwoWay}"
|
||||
ShowGroupPanel="False" RowIndicatorVisibility="Collapsed"
|
||||
telerik:StyleManager.Theme="Crystal">
|
||||
<telerik:RadGridView.Columns>
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization PlcAddrEditor_ColName}" DataMemberBinding="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Width="150"/>
|
||||
<telerik:GridViewComboBoxColumn Header="{loc:Localization PlcAddrEditor_ColType}" DataMemberBinding="{Binding Type, UpdateSourceTrigger=PropertyChanged}"
|
||||
ItemsSourceBinding="{Binding DataContext.SupportedDataTypes, RelativeSource={RelativeSource AncestorType=Window}}" Width="100"/>
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization PlcAddrEditor_ColStartAddr}" DataMemberBinding="{Binding StartAddr, UpdateSourceTrigger=PropertyChanged}" Width="100"/>
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization PlcAddrEditor_ColLength}" DataMemberBinding="{Binding IndexOrLength, UpdateSourceTrigger=PropertyChanged}" Width="100"
|
||||
IsReadOnlyBinding="{Binding IsLengthReadOnly}"/>
|
||||
<telerik:GridViewDataColumn Header="{loc:Localization PlcAddrEditor_ColRemark}" DataMemberBinding="{Binding Remark, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
|
||||
<telerik:GridViewDataColumn Header="" DataMemberBinding="{Binding ValidationError, Mode=OneWay}" IsReadOnly="True" Width="Auto">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="#FFD32F2F"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
</telerik:RadGridView.Columns>
|
||||
</telerik:RadGridView>
|
||||
</DockPanel>
|
||||
</DataTemplate>
|
||||
</telerik:RadTabControl.ContentTemplate>
|
||||
</telerik:RadTabControl>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using XP.Hardware.PLC.ViewModels;
|
||||
|
||||
namespace XP.Hardware.PLC.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC 信号地址定义编辑器窗口 Code-Behind | PLC Signal Address Config Editor Window Code-Behind
|
||||
/// </summary>
|
||||
public partial class PlcAddrConfigEditorWindow : Window
|
||||
{
|
||||
private readonly PlcAddrConfigEditorViewModel _viewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数 | Constructor
|
||||
/// </summary>
|
||||
/// <param name="viewModel">编辑器 ViewModel | Editor ViewModel</param>
|
||||
public PlcAddrConfigEditorWindow(PlcAddrConfigEditorViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = viewModel;
|
||||
DataContext = _viewModel;
|
||||
|
||||
// 绑定窗口关闭回调 | Bind window close action
|
||||
_viewModel.CloseAction = () => Close();
|
||||
|
||||
// 继承主窗口图标 | Inherit main window icon
|
||||
if (Application.Current?.MainWindow != null)
|
||||
{
|
||||
Icon = Application.Current.MainWindow.Icon;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭时执行取消命令 | Execute cancel command on window closing
|
||||
/// </summary>
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
<Window x:Class="XP.Hardware.PLC.Views.PlcTestBenchWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:XP.Hardware.PLC.ViewModels"
|
||||
Title="PLC 测试工具 | PLC Test Bench"
|
||||
Width="1000" Height="700"
|
||||
MinWidth="900" MinHeight="650"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#FFF5F5F5">
|
||||
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
|
||||
|
||||
<!-- 日志条目数据模板 | Log entry data template -->
|
||||
<DataTemplate DataType="{x:Type vm:LogEntry}">
|
||||
<TextBlock Text="{Binding DisplayText}" FontFamily="Consolas" FontSize="12" Margin="2,1">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#FF333333"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Level}" Value="WARN">
|
||||
<Setter Property="Foreground" Value="#FFE68A00"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Level}" Value="ERROR">
|
||||
<Setter Property="Foreground" Value="#FFD32F2F"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="200"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 顶部:连接配置区 | Top: Connection config area -->
|
||||
<GroupBox Grid.Row="0" Header="连接配置 | Connection Config" Foreground="#FF333333" Margin="0,0,0,5"
|
||||
BorderBrush="#FFBDBDBD" Background="#FFFFFFFF">
|
||||
<Grid Margin="5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="60"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="100"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="IP:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding IpAddress, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<TextBlock Grid.Column="2" Text="端口:" VerticalAlignment="Center" Foreground="#FF333333" Margin="5,0,5,0"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding Port, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<TextBlock Grid.Column="4" Text="机架:" VerticalAlignment="Center" Foreground="#FF333333" Margin="5,0,5,0"/>
|
||||
<TextBox Grid.Column="5" Text="{Binding Rack, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<TextBlock Grid.Column="6" Text="槽位:" VerticalAlignment="Center" Foreground="#FF333333" Margin="5,0,5,0"/>
|
||||
<TextBox Grid.Column="7" Text="{Binding Slot, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<TextBlock Grid.Column="8" Text="类型:" VerticalAlignment="Center" Foreground="#FF333333" Margin="5,0,5,0"/>
|
||||
<ComboBox Grid.Column="9" ItemsSource="{Binding PlcTypes}" SelectedItem="{Binding SelectedPlcType}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<!-- 连接/断开按钮和状态 | Connect/Disconnect buttons and status -->
|
||||
<StackPanel Grid.Column="10" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<Button Content="连接" Command="{Binding ConnectCommand}" Width="60" Margin="0,0,5,0" Padding="5,3"/>
|
||||
<Button Content="断开" Command="{Binding DisconnectCommand}" Width="60" Margin="0,0,5,0" Padding="5,3"/>
|
||||
<!-- 状态指示灯 | Status indicator -->
|
||||
<Ellipse Width="14" Height="14" VerticalAlignment="Center" Margin="5,0,5,0">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="Ellipse">
|
||||
<Setter Property="Fill" Value="#FFBDBDBD"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsConnected}" Value="True">
|
||||
<Setter Property="Fill" Value="#FF4CAF50"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Ellipse.Style>
|
||||
</Ellipse>
|
||||
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center" Foreground="#FF666666" FontSize="11" MaxWidth="200" TextTrimming="CharacterEllipsis"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 中部:单点读写区 + 批量读取区 | Middle: Single point R/W + Batch read -->
|
||||
<Grid Grid.Row="1" Margin="0,0,0,5">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- 左侧:单点读写区 | Left: Single point read/write -->
|
||||
<GroupBox Grid.Column="0" Header="单点读写 | Single Point R/W" Foreground="#FF333333" Margin="0,0,3,0"
|
||||
BorderBrush="#FFBDBDBD" Background="#FFFFFFFF">
|
||||
<StackPanel Margin="8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="地址:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,8,5"/>
|
||||
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding PointAddress, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,0,5"/>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="类型:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,8,5"/>
|
||||
<ComboBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding DataTypes}" SelectedItem="{Binding SelectedDataType}" VerticalContentAlignment="Center" Margin="0,0,0,5"/>
|
||||
|
||||
<!-- 字符串长度行(仅 String 类型可见)| String length row (visible only for String type) -->
|
||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="字符串长度:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,8,5"
|
||||
Visibility="{Binding IsStringType, Converter={StaticResource BoolToVisConverter}}"/>
|
||||
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding StringLength, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,0,5"
|
||||
Visibility="{Binding IsStringType, Converter={StaticResource BoolToVisConverter}}"/>
|
||||
|
||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="读取结果:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,8,5"/>
|
||||
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding ReadResult, Mode=OneWay}" IsReadOnly="True" VerticalContentAlignment="Center" Background="#FFF0F0F0" Foreground="#FF1B5E20" Margin="0,0,0,5"/>
|
||||
|
||||
<TextBlock Grid.Row="4" Grid.Column="0" Text="写入值:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,8,5"/>
|
||||
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding WriteValue, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,0,5"/>
|
||||
</Grid>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
||||
<Button Content="读取" Command="{Binding ReadCommand}" Width="70" Margin="0,0,5,0" Padding="5,3"/>
|
||||
<Button Content="写入" Command="{Binding WriteCommand}" Width="70" Margin="0,0,5,0" Padding="5,3"/>
|
||||
<Button Content="切换 (Toggle)" Command="{Binding ToggleBoolCommand}" Width="100" Margin="0,0,5,0" Padding="5,3"
|
||||
Visibility="{Binding IsBoolType, Converter={StaticResource BoolToVisConverter}}"/>
|
||||
<Button Content="连续读取" Command="{Binding StartContinuousReadCommand}" Width="80" Margin="0,0,5,0" Padding="5,3">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#FF4CAF50"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsContinuousReading}" Value="True">
|
||||
<Setter Property="Visibility" Value="Collapsed"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
<Button Content="停止读取" Command="{Binding StopContinuousReadCommand}" Width="80" Padding="5,3"
|
||||
Visibility="{Binding IsContinuousReading, Converter={StaticResource BoolToVisConverter}}">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Background" Value="#FFD32F2F"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 右侧:批量读取区 | Right: Batch read -->
|
||||
<GroupBox Grid.Column="1" Header="批量读取 | Batch Read" Foreground="#FF333333" Margin="3,0,0,0"
|
||||
BorderBrush="#FFBDBDBD" Background="#FFFFFFFF">
|
||||
<DockPanel Margin="8">
|
||||
<Grid DockPanel.Dock="Top">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="60"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" Text="起始地址:" VerticalAlignment="Center" Foreground="#FF333333" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding BatchAddress, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<TextBlock Grid.Column="2" Text="长度:" VerticalAlignment="Center" Foreground="#FF333333" Margin="5,0,5,0"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding BatchLength, UpdateSourceTrigger=PropertyChanged}" VerticalContentAlignment="Center" Margin="0,0,5,0"/>
|
||||
|
||||
<Button Grid.Column="4" Content="批量读取" Command="{Binding BatchReadCommand}" Width="80" Padding="5,3"/>
|
||||
</Grid>
|
||||
|
||||
<!-- 十六进制查看器 | Hex viewer -->
|
||||
<TextBox Margin="0,8,0,0" Text="{Binding HexViewerContent, Mode=OneWay}"
|
||||
IsReadOnly="True" TextWrapping="NoWrap"
|
||||
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
|
||||
FontFamily="Consolas" FontSize="12"
|
||||
Background="#FFF0F0F0" Foreground="#FF1B5E20" BorderBrush="#FFBDBDBD"
|
||||
AcceptsReturn="True"/>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
|
||||
<!-- 底部:日志输出区 | Bottom: Log output area -->
|
||||
<GroupBox Grid.Row="2" Header="操作日志 | Operation Log" Foreground="#FF333333"
|
||||
BorderBrush="#FFBDBDBD" Background="#FFFFFFFF">
|
||||
<DockPanel Margin="5">
|
||||
<Button DockPanel.Dock="Bottom" Content="清除日志" Command="{Binding ClearLogCommand}"
|
||||
HorizontalAlignment="Right" Width="80" Margin="0,5,0,0" Padding="5,3"/>
|
||||
<ListBox x:Name="LogListBox" ItemsSource="{Binding LogEntries}"
|
||||
Background="#FFF9F9F9" BorderBrush="#FFBDBDBD"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding DisplayText}" FontFamily="Consolas" FontSize="12"
|
||||
TextWrapping="Wrap" Margin="2,1">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#FF333333"/>
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Level}" Value="WARN">
|
||||
<Setter Property="Foreground" Value="#FFE68A00"/>
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Level}" Value="ERROR">
|
||||
<Setter Property="Foreground" Value="#FFD32F2F"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,62 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using XP.Common.Logging.Interfaces;
|
||||
using XP.Hardware.Plc.Abstractions;
|
||||
using XP.Hardware.PLC.ViewModels;
|
||||
|
||||
namespace XP.Hardware.PLC.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC 测试工具窗口 Code-Behind | PLC Test Bench Window Code-Behind
|
||||
/// </summary>
|
||||
public partial class PlcTestBenchWindow : Window
|
||||
{
|
||||
private readonly PlcTestBenchViewModel _viewModel;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数 | Constructor
|
||||
/// </summary>
|
||||
/// <param name="plcClient">PLC 客户端接口 | PLC client interface</param>
|
||||
/// <param name="logger">日志服务 | Logger service</param>
|
||||
public PlcTestBenchWindow(IPlcClient plcClient, ILoggerService logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
_viewModel = new PlcTestBenchViewModel(plcClient, logger);
|
||||
DataContext = _viewModel;
|
||||
|
||||
// 继承主窗口图标
|
||||
if (Application.Current?.MainWindow != null)
|
||||
{
|
||||
Icon = Application.Current.MainWindow.Icon;
|
||||
}
|
||||
|
||||
// 订阅日志集合变化,自动滚动到最新条目 | Subscribe to log collection changes for auto-scroll
|
||||
_viewModel.LogEntries.CollectionChanged += LogEntries_CollectionChanged;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 日志集合变化时自动滚动到最新条目 | Auto-scroll to latest entry on collection change
|
||||
/// </summary>
|
||||
private void LogEntries_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && _viewModel.LogEntries.Count > 0)
|
||||
{
|
||||
// 使用 Dispatcher 延迟执行,确保 UI 渲染完成后再滚动 | Use Dispatcher to ensure UI rendering is complete before scrolling
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
LogListBox.ScrollIntoView(_viewModel.LogEntries[_viewModel.LogEntries.Count - 1]);
|
||||
}, System.Windows.Threading.DispatcherPriority.Background);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 窗口关闭时释放资源 | Release resources on window closing
|
||||
/// </summary>
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
_viewModel?.Cleanup();
|
||||
base.OnClosing(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user