将Feature/XP.Common和Feature/XP.Hardware分支合并至Develop/XP.forHardwareAndCommon,完善XPapp注册和相关硬件类库通用类库功能。
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
<Window x:Class="XP.Hardware.PLC.Sentry.Views.SentryMainWindow"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
|
||||
xmlns:views="clr-namespace:XP.Hardware.PLC.Sentry.Views"
|
||||
xmlns:converters="clr-namespace:XP.Hardware.PLC.Sentry.Converters"
|
||||
mc:Ignorable="d"
|
||||
Title="PLC Sentry Monitor"
|
||||
Icon="/XplorerPlane.ico"
|
||||
Width="1200" Height="1000"
|
||||
MinWidth="900" MinHeight="600"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
<converters:LogLevelToColorConverter x:Key="LogLevelToColorConverter"/>
|
||||
<converters:ConnectionStatusToColorConverter x:Key="ConnectionStatusToColorConverter"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<!-- 工具栏 | Toolbar -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
<!-- 信号监控区域 | Signal monitor area -->
|
||||
<RowDefinition Height="*" MinHeight="200"/>
|
||||
<!-- 可拖拽分隔条 | Draggable splitter -->
|
||||
<RowDefinition Height="5"/>
|
||||
<!-- 操作日志面板 | Operation log panel -->
|
||||
<RowDefinition Height="300" MinHeight="100"/>
|
||||
<!-- 状态栏 | Status bar -->
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- === 操作按钮区域 | Action buttons area === -->
|
||||
<DockPanel Grid.Row="0" Margin="8,6" LastChildFill="False">
|
||||
<!-- 左侧:连接、断开 | Left: Connect, Disconnect -->
|
||||
<StackPanel DockPanel.Dock="Left" Orientation="Horizontal">
|
||||
<telerik:RadButton Command="{Binding ConnectCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Content="连接 PLC"
|
||||
ToolTip="连接 PLC | Connect PLC"
|
||||
Padding="10,4" Margin="0,0,6,0"/>
|
||||
<telerik:RadButton Command="{Binding DisconnectCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Content="断开 PLC"
|
||||
ToolTip="断开 PLC | Disconnect PLC"
|
||||
Padding="10,4"/>
|
||||
</StackPanel>
|
||||
<!-- 右侧:PLC 连接管理、刷新信号定义 | Right: PLC Config, Refresh -->
|
||||
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||
<telerik:RadButton Command="{Binding OpenConfigEditorCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Content="PLC 信号地址定义编辑"
|
||||
ToolTip="PLC 信号地址定义编辑器 | PLC Signal Address Definition Editor"
|
||||
Padding="10,4" Margin="0,0,6,0"/>
|
||||
<telerik:RadButton Command="{Binding RefreshSignalDefinitionsCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Content="刷新PLC信号定义"
|
||||
ToolTip="刷新PLC信号定义 | Refresh PLC Signal Definitions"
|
||||
Padding="10,4" Margin="0,0,6,0"/>
|
||||
<telerik:RadButton Command="{Binding OpenSignalDataDemoCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Content="PLC信号读写测试"
|
||||
ToolTip="打开 ISignalDataService DEMO 窗口 | Open Signal Data Demo Window"
|
||||
Padding="10,4"/>
|
||||
</StackPanel>
|
||||
</DockPanel>
|
||||
|
||||
<!-- === 信号监控区域 | Signal monitor area === -->
|
||||
<views:SignalMonitorView Grid.Row="1" Margin="4,4,4,0"
|
||||
DataContext="{Binding}"/>
|
||||
|
||||
<!-- === 可拖拽分隔条 | Draggable GridSplitter === -->
|
||||
<GridSplitter Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Height="5"
|
||||
Background="#FFCCCCCC"
|
||||
ResizeDirection="Rows"
|
||||
ShowsPreview="True"/>
|
||||
|
||||
<!-- === 操作日志面板 | Operation log panel === -->
|
||||
<GroupBox Grid.Row="3" Header="操作日志 | Operation Log" Margin="4,0,4,4">
|
||||
<DockPanel>
|
||||
<!-- 清除日志按钮 | Clear log button -->
|
||||
<telerik:RadButton DockPanel.Dock="Bottom"
|
||||
Content="清除日志 | Clear Log"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Command="{Binding ClearLogCommand}"
|
||||
HorizontalAlignment="Right"
|
||||
Width="120" Margin="0,4,0,0" Padding="5,3"/>
|
||||
|
||||
<!-- 日志表格 | Log grid -->
|
||||
<telerik:RadGridView ItemsSource="{Binding LogEntries}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="True"
|
||||
RowIndicatorVisibility="Collapsed"
|
||||
ShowGroupPanel="False"
|
||||
ShowColumnHeaders="True"
|
||||
CanUserFreezeColumns="False"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserSortColumns="False"
|
||||
CanUserResizeColumns="True"
|
||||
IsFilteringAllowed="False"
|
||||
SelectionMode="Single"
|
||||
FontFamily="Consolas"
|
||||
FontSize="12"
|
||||
Background="#FFF9F9F9"
|
||||
BorderBrush="#FFBDBDBD"
|
||||
Margin="0,5,0,0">
|
||||
<telerik:RadGridView.Columns>
|
||||
<!-- 时间戳列 | Timestamp column -->
|
||||
<telerik:GridViewDataColumn Header="时间 | Time"
|
||||
DataMemberBinding="{Binding TimestampDisplay}"
|
||||
Width="110"
|
||||
IsReadOnly="True"/>
|
||||
|
||||
<!-- 级别列 | Level column -->
|
||||
<telerik:GridViewDataColumn Header="级别 | Level"
|
||||
DataMemberBinding="{Binding Level}"
|
||||
Width="70"
|
||||
IsReadOnly="True">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="{Binding Level, Converter={StaticResource LogLevelToColorConverter}}"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
|
||||
<!-- 消息列 | Message column -->
|
||||
<telerik:GridViewDataColumn Header="消息 | Message"
|
||||
DataMemberBinding="{Binding Message}"
|
||||
Width="*"
|
||||
IsReadOnly="True">
|
||||
<telerik:GridViewDataColumn.CellStyle>
|
||||
<Style TargetType="telerik:GridViewCell">
|
||||
<Setter Property="Foreground" Value="{Binding Level, Converter={StaticResource LogLevelToColorConverter}}"/>
|
||||
</Style>
|
||||
</telerik:GridViewDataColumn.CellStyle>
|
||||
</telerik:GridViewDataColumn>
|
||||
</telerik:RadGridView.Columns>
|
||||
</telerik:RadGridView>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- === 状态栏 | Status bar === -->
|
||||
<StatusBar Grid.Row="4" Background="#FFF0F0F0" BorderBrush="#FFCCCCCC" BorderThickness="0,1,0,0">
|
||||
<!-- 连接状态指示灯和文本 | Connection status indicator and text -->
|
||||
<StatusBarItem>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<!-- 连接状态指示灯(绿/灰/黄)| Connection status indicator (green/gray/yellow) -->
|
||||
<Ellipse Width="12" Height="12" VerticalAlignment="Center" Margin="4,0,6,0">
|
||||
<Ellipse.Fill>
|
||||
<MultiBinding Converter="{StaticResource ConnectionStatusToColorConverter}">
|
||||
<Binding Path="IsConnected"/>
|
||||
<Binding Path="StatusText"/>
|
||||
</MultiBinding>
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
<TextBlock Text="{Binding StatusText}" VerticalAlignment="Center"
|
||||
Foreground="#FF666666" FontSize="12"/>
|
||||
</StackPanel>
|
||||
</StatusBarItem>
|
||||
<!-- 分隔符 | Separator -->
|
||||
<Separator/>
|
||||
<!-- 应用信息(右侧)| Application info (right side) -->
|
||||
<StatusBarItem HorizontalAlignment="Right">
|
||||
<TextBlock Text="PLC Sentry Monitor v1.0" Foreground="#FF999999" FontSize="11"/>
|
||||
</StatusBarItem>
|
||||
</StatusBar>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,17 @@
|
||||
using System.Windows;
|
||||
using XP.Hardware.PLC.Sentry.ViewModels;
|
||||
|
||||
namespace XP.Hardware.PLC.Sentry.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// PLC Sentry Monitor 主窗口 | PLC Sentry Monitor main window
|
||||
/// </summary>
|
||||
public partial class SentryMainWindow : Window
|
||||
{
|
||||
public SentryMainWindow(SentryMainViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
<Window x:Class="XP.App.Views.SignalDataDemoWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="ISignalDataService DEMO"
|
||||
Width="800" Height="650"
|
||||
MinWidth="700" MinHeight="550"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Background="#FFF5F5F5">
|
||||
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid Margin="10">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- 连接区 -->
|
||||
<GroupBox Grid.Row="0" Header="1. 连接 PLC 并加载信号定义" Margin="0,0,0,5">
|
||||
<StackPanel Margin="8">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="信号定义文件:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding XmlFilePath, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<Button Grid.Column="2" Content="连接并加载" Command="{Binding ConnectAndLoadCommand}"
|
||||
Width="90" Padding="5,3" Margin="0,0,8,0"/>
|
||||
<StackPanel Grid.Column="3" Orientation="Horizontal">
|
||||
<Ellipse Width="12" Height="12" VerticalAlignment="Center" Margin="0,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>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 信号读取区(批量缓存/单点自动路由)-->
|
||||
<GroupBox Grid.Row="1" Header="2. 信号读取 (GetValueByName - 自动路由批量缓存/单点读取)" Margin="0,0,0,5">
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="150"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="信号名称:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding ReadSignalName, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<Button Grid.Column="2" Content="读取" Command="{Binding CacheReadCommand}"
|
||||
Width="60" Padding="5,3" Margin="0,0,8,0"/>
|
||||
<TextBlock Grid.Column="3" Text="结果:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="4" Text="{Binding ReadResult, Mode=OneWay}" IsReadOnly="True"
|
||||
VerticalContentAlignment="Center" Background="#FFF0F0F0" Foreground="#FF1B5E20"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 队列写入区 -->
|
||||
<GroupBox Grid.Row="2" Header="3. 队列写入 (EnqueueWrite)" Margin="0,0,0,5">
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="信号名称:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding QueueSignalName, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBlock Grid.Column="2" Text="写入值:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding QueueWriteValue, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<Button Grid.Column="4" Content="入队写入" Command="{Binding QueueWriteCommand}"
|
||||
Width="70" Padding="5,3"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 直接写入+回读校验区 -->
|
||||
<GroupBox Grid.Row="3" Header="4. 直接写入+回读校验 (WriteDirectWithVerify)" Margin="0,0,0,5">
|
||||
<Grid Margin="8">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="120"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock Grid.Column="0" Text="信号名称:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="1" Text="{Binding DirectSignalName, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBlock Grid.Column="2" Text="写入值:" VerticalAlignment="Center" Margin="0,0,5,0"/>
|
||||
<TextBox Grid.Column="3" Text="{Binding DirectWriteValue, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center" Margin="0,0,8,0"/>
|
||||
<Button Grid.Column="4" Content="直接写入" Command="{Binding DirectWriteCommand}"
|
||||
Width="70" Padding="5,3"/>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<!-- 日志区 -->
|
||||
<GroupBox Grid.Row="4" Header="操作日志">
|
||||
<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}"
|
||||
FontFamily="Consolas" FontSize="12"
|
||||
Background="#FFF9F9F9" BorderBrush="#FFBDBDBD"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
||||
ScrollViewer.VerticalScrollBarVisibility="Auto">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Padding" Value="2,1"/>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
</ListBox>
|
||||
</DockPanel>
|
||||
</GroupBox>
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using XP.App.ViewModels;
|
||||
using XP.Common.Logging.Interfaces;
|
||||
using XP.Hardware.Plc.Abstractions;
|
||||
using XP.Hardware.Plc.Services;
|
||||
using XP.Hardware.PLC.Configs;
|
||||
|
||||
namespace XP.App.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// ISignalDataService DEMO 窗口
|
||||
/// </summary>
|
||||
public partial class SignalDataDemoWindow : Window
|
||||
{
|
||||
public SignalDataDemoWindow(
|
||||
PlcService plcService,
|
||||
ISignalDataService signalService,
|
||||
ConfigLoader configLoader,
|
||||
ILoggerService logger)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var vm = new SignalDataDemoViewModel(plcService, signalService, configLoader, logger);
|
||||
DataContext = vm;
|
||||
|
||||
if (Application.Current?.MainWindow != null)
|
||||
Icon = Application.Current.MainWindow.Icon;
|
||||
|
||||
// 日志自动滚动
|
||||
vm.LogEntries.CollectionChanged += (s, e) =>
|
||||
{
|
||||
if (e.Action == NotifyCollectionChangedAction.Add && vm.LogEntries.Count > 0)
|
||||
{
|
||||
Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
LogListBox.ScrollIntoView(vm.LogEntries[vm.LogEntries.Count - 1]);
|
||||
}, System.Windows.Threading.DispatcherPriority.Background);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<UserControl x:Class="XP.Hardware.PLC.Sentry.Views.SignalMonitorView"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
|
||||
xmlns:views="clr-namespace:XP.Hardware.PLC.Sentry.Views"
|
||||
xmlns:converters="clr-namespace:XP.Hardware.PLC.Sentry.Converters"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
|
||||
<UserControl.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
|
||||
<converters:NullOrEmptyToVisibilityConverter x:Key="NullToCollapsedConverter"/>
|
||||
|
||||
<!-- 读取错误时的前景色样式 | Foreground style for read errors -->
|
||||
<Style x:Key="ReadErrorCellStyle" TargetType="telerik:GridViewCell">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding HasReadError}" Value="True">
|
||||
<Setter Property="Foreground" Value="#FFD32F2F"/>
|
||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
|
||||
<!-- === 写入控件模板 | Write control templates === -->
|
||||
|
||||
<!-- bool 类型:ToggleButton | Bool type: ToggleButton -->
|
||||
<DataTemplate x:Key="BoolWriteTemplate">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<ToggleButton IsChecked="{Binding WriteValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Content="{Binding WriteValue, TargetNullValue=False}"
|
||||
MinWidth="60" Padding="6,2"
|
||||
HorizontalAlignment="Stretch"/>
|
||||
<TextBlock Text="{Binding ValidationError}"
|
||||
Foreground="#FFD32F2F" FontSize="10"
|
||||
Visibility="{Binding ValidationError, Converter={StaticResource NullToCollapsedConverter}}"
|
||||
TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- 整数类型:RadNumericUpDown(整数模式)| Integer type: RadNumericUpDown (integer mode) -->
|
||||
<DataTemplate x:Key="IntegerWriteTemplate">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<telerik:RadNumericUpDown Value="{Binding WriteValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
NumberDecimalDigits="0"
|
||||
IsInteger="True"
|
||||
MinWidth="80"
|
||||
HorizontalAlignment="Stretch"
|
||||
UpdateValueEvent="PropertyChanged"/>
|
||||
<TextBlock Text="{Binding ValidationError}"
|
||||
Foreground="#FFD32F2F" FontSize="10"
|
||||
Visibility="{Binding ValidationError, Converter={StaticResource NullToCollapsedConverter}}"
|
||||
TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- 浮点类型:RadNumericUpDown(浮点模式)| Float type: RadNumericUpDown (float mode) -->
|
||||
<DataTemplate x:Key="FloatWriteTemplate">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<telerik:RadNumericUpDown Value="{Binding WriteValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
NumberDecimalDigits="4"
|
||||
IsInteger="False"
|
||||
MinWidth="80"
|
||||
HorizontalAlignment="Stretch"
|
||||
UpdateValueEvent="PropertyChanged"/>
|
||||
<TextBlock Text="{Binding ValidationError}"
|
||||
Foreground="#FFD32F2F" FontSize="10"
|
||||
Visibility="{Binding ValidationError, Converter={StaticResource NullToCollapsedConverter}}"
|
||||
TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- 字符串类型:TextBox | String type: TextBox -->
|
||||
<DataTemplate x:Key="StringWriteTemplate">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBox Text="{Binding WriteValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinWidth="80"
|
||||
HorizontalAlignment="Stretch"
|
||||
Padding="2"/>
|
||||
<TextBlock Text="{Binding ValidationError}"
|
||||
Foreground="#FFD32F2F" FontSize="10"
|
||||
Visibility="{Binding ValidationError, Converter={StaticResource NullToCollapsedConverter}}"
|
||||
TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
|
||||
<!-- 写入值模板选择器 | Write value template selector -->
|
||||
<views:WriteValueTemplateSelector x:Key="WriteValueTemplateSelector"
|
||||
BoolTemplate="{StaticResource BoolWriteTemplate}"
|
||||
IntegerTemplate="{StaticResource IntegerWriteTemplate}"
|
||||
FloatTemplate="{StaticResource FloatWriteTemplate}"
|
||||
StringTemplate="{StaticResource StringWriteTemplate}"/>
|
||||
</UserControl.Resources>
|
||||
|
||||
<Grid>
|
||||
<!-- 无数据时的占位提示 | Placeholder when no data -->
|
||||
<TextBlock Text="请加载信号定义文件 | Please load signal definition file"
|
||||
HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||
Foreground="#FF999999" FontSize="14"
|
||||
Visibility="{Binding HasNoGroups, Converter={StaticResource BoolToVis}}"/>
|
||||
|
||||
<!-- 信号分组标签页 | Signal group tabs -->
|
||||
<telerik:RadTabControl ItemsSource="{Binding SignalGroups}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
DisplayMemberPath="TabHeader"
|
||||
OverflowMode="Scroll"
|
||||
TabStripPlacement="Top">
|
||||
<telerik:RadTabControl.ContentTemplate>
|
||||
<DataTemplate>
|
||||
<!-- 每个 Tab 页内的信号表格 | Signal grid within each tab -->
|
||||
<telerik:RadGridView ItemsSource="{Binding Signals}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
AutoGenerateColumns="False"
|
||||
IsReadOnly="False"
|
||||
RowIndicatorVisibility="Collapsed"
|
||||
ShowGroupPanel="False"
|
||||
CanUserFreezeColumns="False"
|
||||
CanUserReorderColumns="True"
|
||||
CanUserSortColumns="True"
|
||||
CanUserResizeColumns="True"
|
||||
ColumnWidth="*"
|
||||
SelectionMode="Single"
|
||||
IsFilteringAllowed="False"
|
||||
ShowColumnSortIndexes="False">
|
||||
<telerik:RadGridView.Columns>
|
||||
<!-- 名称列 | Name column -->
|
||||
<telerik:GridViewDataColumn Header="名称 | Name"
|
||||
DataMemberBinding="{Binding Name}"
|
||||
IsReadOnly="True"
|
||||
Width="200"/>
|
||||
|
||||
<!-- 类型列 | Type column -->
|
||||
<telerik:GridViewDataColumn Header="类型 | Type"
|
||||
DataMemberBinding="{Binding Type}"
|
||||
IsReadOnly="True"
|
||||
Width="80"/>
|
||||
|
||||
<!-- 地址列 | Address column -->
|
||||
<telerik:GridViewDataColumn Header="地址 | Address"
|
||||
DataMemberBinding="{Binding AddressDisplay}"
|
||||
IsReadOnly="True"
|
||||
Width="120"/>
|
||||
|
||||
<!-- 当前值列 | Current value column -->
|
||||
<telerik:GridViewDataColumn Header="当前值 | Value"
|
||||
DataMemberBinding="{Binding CurrentValue}"
|
||||
IsReadOnly="True"
|
||||
Width="120"
|
||||
CellStyle="{StaticResource ReadErrorCellStyle}"/>
|
||||
|
||||
<!-- 写入值列(根据类型动态选择控件)| Write value column (dynamic control by type) -->
|
||||
<telerik:GridViewColumn Header="写入值 | Write" Width="140">
|
||||
<telerik:GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl Content="{Binding}"
|
||||
ContentTemplateSelector="{StaticResource WriteValueTemplateSelector}"/>
|
||||
</DataTemplate>
|
||||
</telerik:GridViewColumn.CellTemplate>
|
||||
</telerik:GridViewColumn>
|
||||
|
||||
<!-- 操作按钮列 | Action button column -->
|
||||
<telerik:GridViewColumn Header="操作 | Action" Width="140">
|
||||
<telerik:GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
|
||||
<telerik:RadButton Content="应用" Command="{Binding ApplyCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Width="50" Margin="0,0,4,0" Padding="4,2"
|
||||
ToolTip="队列写入 | Queue Write"/>
|
||||
<telerik:RadButton Content="直写" Command="{Binding DirectWriteCommand}"
|
||||
telerik:StyleManager.Theme="Crystal"
|
||||
Width="50" Padding="4,2"
|
||||
ToolTip="直接写入+回读校验 | Direct Write with Verify"/>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</telerik:GridViewColumn.CellTemplate>
|
||||
</telerik:GridViewColumn>
|
||||
|
||||
<!-- 备注列 | Remark column -->
|
||||
<telerik:GridViewDataColumn Header="备注 | Remark"
|
||||
DataMemberBinding="{Binding Remark}"
|
||||
IsReadOnly="True"
|
||||
Width="*"/>
|
||||
</telerik:RadGridView.Columns>
|
||||
</telerik:RadGridView>
|
||||
</DataTemplate>
|
||||
</telerik:RadTabControl.ContentTemplate>
|
||||
</telerik:RadTabControl>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace XP.Hardware.PLC.Sentry.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// 信号监控视图 | Signal monitor view
|
||||
/// </summary>
|
||||
public partial class SignalMonitorView : UserControl
|
||||
{
|
||||
public SignalMonitorView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using XP.Hardware.PLC.Sentry.ViewModels;
|
||||
|
||||
namespace XP.Hardware.PLC.Sentry.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// 写入值控件模板选择器,根据信号数据类型选择不同的写入控件 | Write value template selector, selects different write controls based on signal data type
|
||||
/// bool → ToggleButton, byte/short/int → RadNumericUpDown(整数), single/double → RadNumericUpDown(浮点), string → TextBox
|
||||
/// </summary>
|
||||
public class WriteValueTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
/// <summary>
|
||||
/// bool 类型写入模板 | Bool type write template
|
||||
/// </summary>
|
||||
public DataTemplate BoolTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 整数类型写入模板(byte, short, int)| Integer type write template
|
||||
/// </summary>
|
||||
public DataTemplate IntegerTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 浮点类型写入模板(single, double)| Float type write template
|
||||
/// </summary>
|
||||
public DataTemplate FloatTemplate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 字符串类型写入模板 | String type write template
|
||||
/// </summary>
|
||||
public DataTemplate StringTemplate { get; set; }
|
||||
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||
{
|
||||
if (item is SignalRowViewModel row)
|
||||
{
|
||||
return row.Type?.ToLowerInvariant() switch
|
||||
{
|
||||
"bool" => BoolTemplate,
|
||||
"byte" or "short" or "int" => IntegerTemplate,
|
||||
"single" or "double" => FloatTemplate,
|
||||
"string" => StringTemplate,
|
||||
_ => StringTemplate // 默认使用文本框 | Default to TextBox
|
||||
};
|
||||
}
|
||||
|
||||
return base.SelectTemplate(item, container);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user