Shun преди 2 години
родител
ревизия
03171d97f9
променени са 28 файла, в които са добавени 2948 реда и са изтрити 277 реда
  1. 4 0
      README.md
  2. 59 0
      src/YSAI.Core.Wpf/resources/svg/WindowSvg.xaml
  3. 1 1
      src/YSAI.Opc/YSAI.Opc.csproj
  4. 8 47
      src/YSAI.Tool.Wpf/Main.xaml.cs
  5. 343 0
      src/YSAI.Tool.Wpf/Test.xaml
  6. 28 0
      src/YSAI.Tool.Wpf/Test.xaml.cs
  7. 197 0
      src/YSAI.Tool.Wpf/TestController.cs
  8. 2 2
      src/YSAI.Tool.Wpf/YSAI.Tool.Wpf.csproj
  9. 2 1
      src/YSAI.Tool.Wpf/controllers/MainController.cs
  10. 9 0
      src/YSAI.Tool.Wpf/controllers/SerialController.cs
  11. 9 0
      src/YSAI.Tool.Wpf/controllers/TcpClientController.cs
  12. 13 28
      src/YSAI.Tool.Wpf/controllers/TcpServiceController.cs
  13. 981 0
      src/YSAI.Tool.Wpf/controllers/UaClientController.cs
  14. 9 0
      src/YSAI.Tool.Wpf/controllers/UdpController.cs
  15. 9 0
      src/YSAI.Tool.Wpf/controllers/WsClientController.cs
  16. 13 28
      src/YSAI.Tool.Wpf/controllers/WsServiceController.cs
  17. 66 0
      src/YSAI.Tool.Wpf/data/NodeMessageStructuralBody.cs
  18. 58 0
      src/YSAI.Tool.Wpf/data/NodeStructuralBody.cs
  19. 63 26
      src/YSAI.Tool.Wpf/views/Serial.xaml
  20. 63 26
      src/YSAI.Tool.Wpf/views/TcpClient.xaml
  21. 63 26
      src/YSAI.Tool.Wpf/views/TcpService.xaml
  22. 602 0
      src/YSAI.Tool.Wpf/views/UaClient.xaml
  23. 15 0
      src/YSAI.Tool.Wpf/views/UaClient.xaml.cs
  24. 63 26
      src/YSAI.Tool.Wpf/views/Udp.xaml
  25. 63 26
      src/YSAI.Tool.Wpf/views/WsClient.xaml
  26. 63 26
      src/YSAI.Tool.Wpf/views/WsService.xaml
  27. 94 14
      src/YSAI.Tool.Wpf/views/WsService.xaml.cs
  28. 48 0
      src/YSAI.Unility.Windows/WpfHelperTool.cs

+ 4 - 0
README.md

@@ -556,3 +556,7 @@ while(true)
 3. 串口、Tcp客户端改造完成
 4. 优化终端展示界面
 5. 新增第一次打开显示默认界面
+
+#### 2023-12-20
+1. 优化工具界面
+2. 改成OPCUA客户端界面

Файловите разлики са ограничени, защото са твърде много
+ 59 - 0
src/YSAI.Core.Wpf/resources/svg/WindowSvg.xaml


+ 1 - 1
src/YSAI.Opc/YSAI.Opc.csproj

@@ -16,7 +16,7 @@
     <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.76" />
+    <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.106" />
     <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </ItemGroup>
 </Project>

+ 8 - 47
src/YSAI.Tool.Wpf/Main.xaml.cs

@@ -1,10 +1,9 @@
 using System.Windows;
-using System.Windows.Media;
 using Wpf.Ui.Controls;
 using YSAI.Core.Wpf;
 using YSAI.Langs;
 using YSAI.Tool.Wpf.views;
-using MessageBox = YSAI.Core.Wpf.MessageBox;
+using YSAI.Unility.Windows;
 namespace YSAI.Tool.Wpf
 {
     /// <summary>
@@ -23,23 +22,26 @@ namespace YSAI.Tool.Wpf
 
             //皮肤变化设置控件模版
             WindowHelper_OnSkinSwitchEvent(WindowHelper.SkinName, null);
+
             //特殊解决方案,无法直接用此控件NAME 只能使用此方法来设置第一次打开显示的界面
             Task.Run(() =>
             {
                 Thread.Sleep(50);
                 System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
                 {
-                    List<NavigationView> navigationViews = FindVisualChild<NavigationView>(this);
+                    List<NavigationView> navigationViews = WpfHelperTool.FindVisualChild<NavigationView>(this);
                     if (navigationViews.Count > 0)
                     {
                         //第一次打开显示的界面
-                        navigationViews[0].Navigate(typeof(Serial));
+                        navigationViews[0].Navigate(typeof(UaClient));
                     }
                 });
             });
 
-
         }
+
+
+
         /// <summary>
         /// 语言发生变化
         /// </summary>
@@ -102,48 +104,7 @@ namespace YSAI.Tool.Wpf
                 sn = SkinName;
 
             }
-
-
-        }
-        /// <summary>
-        /// 检索模版下指定控件集
-        /// </summary>
-        /// <typeparam name="T"></typeparam>
-        /// <param name="obj"></param>
-        /// <returns></returns>
-        List<T> FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
-        {
-            try
-            {
-                List<T> TList = new List<T> { };
-                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
-                {
-                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
-                    if (child != null && child is T)
-                    {
-                        TList.Add((T)child);
-                        List<T> childOfChildren = FindVisualChild<T>(child);
-                        if (childOfChildren != null)
-                        {
-                            TList.AddRange(childOfChildren);
-                        }
-                    }
-                    else
-                    {
-                        List<T> childOfChildren = FindVisualChild<T>(child);
-                        if (childOfChildren != null)
-                        {
-                            TList.AddRange(childOfChildren);
-                        }
-                    }
-                }
-                return TList;
-            }
-            catch (Exception ee)
-            {
-                MessageBox.Show(ee.Message);
-                return null;
-            }
         }
+
     }
 }

+ 343 - 0
src/YSAI.Tool.Wpf/Test.xaml

@@ -0,0 +1,343 @@
+<UserControl x:Class="YSAI.Tool.Wpf.Test"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:YSAI.Tool.Wpf"
+                                     xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+            xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+            xmlns:pt="http://propertytools.org/wpf"
+            xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+            xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+            xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+            xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+            Background="{DynamicResource ContentBackgroundPicture}">
+    <UserControl.DataContext>
+        <c:TcpClientController />
+    </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeDataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="auto"/>
+                    </Grid.RowDefinitions>
+                   
+                    <!--导入导出-->
+                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />  
+                    </StackPanel>
+                    <!--属性表格-->
+                    <Grid Grid.Row="1" Panel.ZIndex="1">
+                        <Grid.Resources>
+                            <ResourceDictionary>
+                                <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="HorizontalAlignment" Value="Left"/>
+                                </Style>
+                                <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource DefaultComboBox}" >
+                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="Background" Value="White"/>
+                                    <Setter Property="VerticalAlignment" Value="Center"/>
+                                    <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
+                                </Style>
+                                <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" MinWidth="600">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+
+                       
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid Grid.Row="0" Grid.Column="1"  Margin="0,-40,0,0">
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
+                                    <btn:ButtonControl  Grid.Column="5"  Width="80"   Command="{Binding Start}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource Open}"
+                                           Content="打开"/>
+
+                                    <btn:ButtonControl  Grid.Column="6"  Width="80"  Command="{Binding Stop}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource CloseBase}"
+                                           Content="关闭"/>
+                                </StackPanel>
+                            </Grid>
+                            <!--发送区域-->
+                            <Grid Grid.Row="1" Grid.Column="1">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition/>
+                                    <RowDefinition/>
+                                </Grid.RowDefinitions>
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30">
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <btn:ButtonControl  Grid.Column="3"  Width="80"  Command="{Binding Send}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+                                                            IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                            BorderBrush="{DynamicResource Control.Border.Color}"
+                                                            IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                            Foreground="{DynamicResource Font.Content.Foreground}"
+                                                            Icon="{DynamicResource Send}"
+                                                            Content="发送"/>
+                                </StackPanel>
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Grid.Row="1" Grid.ColumnSpan="8" Width="auto" Margin="0,0,0,0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid>
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto"/>
+                                                    <ColumnDefinition Width="*"/>
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Data}" Width="14" />
+                                                <TextBlock Text="数据" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+                                    <TextBox  Padding="5" Style="{DynamicResource TextBoxStyle2}" Height="230" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Text="{Binding SendData}" />
+                                </GroupBox>
+                            </Grid>
+                        </Grid>
+
+
+
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+                    </GroupBox>
+                    <!--信息-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,5,0,0"  Grid.Row="1">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Info}" Width="14" />
+                                    <TextBlock Text="信息" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition />
+                            </Grid.RowDefinitions>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,-40,0,0">
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <btn:ButtonControl  Width="80"  Command="{Binding Clear}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+Foreground="{DynamicResource Font.Content.Foreground}"
+Icon="{DynamicResource Clear}"
+Content="清空"/>
+                            </StackPanel>
+                            <TextBox Grid.Row="1" Padding="5" Grid.ColumnSpan="2" Style="{DynamicResource TextBoxStyle2}"  FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"  Text="{Binding Info}" >
+                                <i:Interaction.Triggers>
+                                    <i:EventTrigger EventName="TextChanged">
+                                        <mvvm:EventCommand  Command="{Binding Info_TextChanged}" />
+                                    </i:EventTrigger>
+                                </i:Interaction.Triggers>
+                            </TextBox>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
+            </Grid>
+        </GroupBox>
+    </Border>
+</UserControl>
+

+ 28 - 0
src/YSAI.Tool.Wpf/Test.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace YSAI.Tool.Wpf
+{
+    /// <summary>
+    /// Test.xaml 的交互逻辑
+    /// </summary>
+    public partial class Test : UserControl
+    {
+        public Test()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 197 - 0
src/YSAI.Tool.Wpf/TestController.cs

@@ -0,0 +1,197 @@
+using System.IO;
+using System.Windows;
+using System.Windows.Input;
+using YSAI.Core.communication.net.ws.client;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Unility;
+using static YSAI.Core.communication.net.ws.client.WsClientData;
+
+
+namespace YSAI.Tool.Wpf
+{
+    public class TestController : NotifyObject
+    {
+        public TestController()
+        {
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Ws 服务端工具";
+            //配置文件名
+            FileName = typeof(WsClientData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Visible;
+            //Hex是否显示
+            HexVisibility = Visibility.Visible;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
+        }
+
+        #region 统一需要的数据
+        /// <summary>
+        /// 导出的文件名
+        /// </summary>
+        private string FileName { get; set; }
+        /// <summary>
+        /// 工具标题
+        /// </summary>
+        public string ToolTitle
+        {
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
+        }
+        /// <summary>
+        /// 数据源
+        /// </summary>
+        public Basics BasicsData
+        {
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
+        }
+
+        /// <summary>
+        /// 导入基础数据命令
+        /// </summary>
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (basics == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
+        {
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new CommandX(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
+        #endregion 统一需要的数据
+    }
+}

+ 2 - 2
src/YSAI.Tool.Wpf/YSAI.Tool.Wpf.csproj

@@ -17,7 +17,7 @@
 		<PackageReference Include="PropertyTools.Wpf" Version="3.1.0" />
 		<PackageReference Include="WPF-UI" Version="3.0.0-preview.13" />
 		<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
-		<!--<PackageReference Include="YSAI.AllenBradley" Version="23.353.7802" />
+		<PackageReference Include="YSAI.AllenBradley" Version="23.353.7802" />
 		<PackageReference Include="YSAI.Beckhoff" Version="23.353.7802" />
 		<PackageReference Include="YSAI.DB" Version="23.353.7802" />
 		<PackageReference Include="YSAI.Kafka" Version="23.352.38022" />
@@ -31,7 +31,7 @@
 		<PackageReference Include="YSAI.Opc" Version="23.353.7802" />
 		<PackageReference Include="YSAI.RabbitMQ" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Redis" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Siemens" Version="23.353.7802" />-->
+		<PackageReference Include="YSAI.Siemens" Version="23.353.7802" />
 	</ItemGroup>
 	<ItemGroup>
 		<ProjectReference Include="..\YSAI.Core.Wpf\YSAI.Core.Wpf.csproj" />

+ 2 - 1
src/YSAI.Tool.Wpf/controllers/MainController.cs

@@ -32,7 +32,7 @@ namespace YSAI.Tool.Wpf.controllers
                         Icon = new SymbolIcon { Symbol = SymbolRegular.Toolbox12 , Filled = true },
                         MenuItems = new object[]
                         {
-                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "UA"), SymbolRegular.DocumentTextToolbox24, typeof(AboutUs)),
+                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "UA"), SymbolRegular.DocumentTextToolbox24, typeof(UaClient)),
                             CreationControl(string.Format("{0,-8}{1}", "[ 服务端 ]", "UA"), SymbolRegular.DesktopToolbox24, typeof(AboutUs)),
                             CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "DA ( x86 run )"), SymbolRegular.ClockToolbox24, typeof(AboutUs)),
                             CreationControl(string.Format("{0,-8}{1}", "[ HTTP ]", "DA"), SymbolRegular.BookToolbox24, typeof(AboutUs))
@@ -75,6 +75,7 @@ namespace YSAI.Tool.Wpf.controllers
                   },
                   CreationControl("Serial",SymbolRegular.Toolbox12,typeof(Serial)),
                   CreationControl("Svg",SymbolRegular.Toolbox12,typeof(Svg)),
+                  CreationControl("Test",SymbolRegular.Toolbox12,typeof(Test)),
             };
 
             FooterMenuItemsSource = new ObservableCollection<object>

+ 9 - 0
src/YSAI.Tool.Wpf/controllers/SerialController.cs

@@ -188,6 +188,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
 

+ 9 - 0
src/YSAI.Tool.Wpf/controllers/TcpClientController.cs

@@ -187,6 +187,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
 

+ 13 - 28
src/YSAI.Tool.Wpf/controllers/TcpServiceController.cs

@@ -194,6 +194,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
 
@@ -387,40 +396,16 @@ namespace YSAI.Tool.Wpf.controllers
             {
                 public string IP
                 {
-                    get
-                    {
-                        return ip;
-                    }
-                    set
-                    {
-                        if (value != null && !value.Equals(ip))
-                        {
-                            ip = value;
-                            RaisePropertyChanged("IP");
-                        }
-                    }
+                    get => GetProperty(() => IP);
+                    set => SetProperty(() => IP, value);
                 }
 
-                private string ip;
-
                 public string Port
                 {
-                    get
-                    {
-                        return port;
-                    }
-                    set
-                    {
-                        if (value != null && !value.Equals(port))
-                        {
-                            port = value;
-                            RaisePropertyChanged("Port");
-                        }
-                    }
+                    get => GetProperty(() => Port);
+                    set => SetProperty(() => Port, value);
                 }
 
-                private string port;
-
                 /// <summary>
                 /// 地址与端口
                 /// </summary>

+ 981 - 0
src/YSAI.Tool.Wpf/controllers/UaClientController.cs

@@ -0,0 +1,981 @@
+using Newtonsoft.Json;
+using Opc.Ua;
+using System.Collections.Concurrent;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using YSAI.Core.Wpf;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Opc.ua.client;
+using YSAI.Opc.ua.service.core;
+using YSAI.Tool.Wpf.data;
+using YSAI.Unility;
+using static YSAI.Opc.ua.client.OpcUaClientData;
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class UaClientController : NotifyObject
+    {
+        public UaClientController()
+        {
+            //当皮肤切换触发事件
+            WindowHelper.OnSkinSwitchEvent += WindowHelper_OnSkinSwitchEvent;
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "OpcUa 客户端工具";
+            //配置文件名
+            FileName = typeof(OpcUaClientData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Collapsed;
+            //Hex是否显示
+            HexVisibility = Visibility.Collapsed;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
+        }
+        private void WindowHelper_OnSkinSwitchEvent(object? sender, EventArgs e)
+        {
+
+        }
+
+        #region 统一需要的数据
+        /// <summary>
+        /// 导出的文件名
+        /// </summary>
+        private string FileName { get; set; }
+        /// <summary>
+        /// 工具标题
+        /// </summary>
+        public string ToolTitle
+        {
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
+        }
+        /// <summary>
+        /// 数据源
+        /// </summary>
+        public Basics BasicsData
+        {
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
+        }
+
+        /// <summary>
+        /// 导入基础数据命令
+        /// </summary>
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (basics == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
+        {
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new CommandX(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool? BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
+
+        #endregion 统一需要的数据
+
+        /// <summary>
+        /// 数据类型
+        /// </summary>
+        public int DataType
+        {
+            get => GetProperty(() => DataType);
+            set => SetProperty(() => DataType, value);
+        }
+
+        /// <summary>
+        /// 隐藏节点浏览命令
+        /// </summary>
+        public ICommand ToggleButton_Unchecked { get => new CommandX<RoutedEventArgs>(OnToggleButton_Unchecked); }
+        private void OnToggleButton_Unchecked(RoutedEventArgs e)
+        {
+            BasicsData_ToggleButtonIsChecked = false;
+            if (tokenSource != null)
+            {
+                tokenSource.Cancel();
+                tokenSource = null;
+            }
+            Node?.Clear();
+            Node = null;
+        }
+        /// <summary>
+        /// 加载节点的生命周期
+        /// </summary>
+        private CancellationTokenSource tokenSource;
+        /// <summary>
+        /// 显示节点浏览命令
+        /// </summary>
+        public ICommand ToggleButton_Checked { get => new CommandX<RoutedEventArgs>(OnToggleButton_Checked); }
+        private void OnToggleButton_Checked(RoutedEventArgs e)
+        {
+            if (communication != null && communication.GetStatus().State)
+            {
+                BasicsData_ToggleButtonIsChecked = true;
+                if (Node == null)
+                {
+                    if (tokenSource == null)
+                    {
+                        tokenSource = new CancellationTokenSource();
+                    }
+                    //实例化对象
+                    Node = new ObservableCollection<NodeStructuralBody>();
+                    //获取所有节点
+                    GetAllNode(tokenSource);
+                }
+            }
+
+        }
+
+        /// <summary>
+        /// 通信
+        /// </summary>
+        private OpcUaClientOperate communication;
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public ICommand Start { get => new CommandX(OnStart); }
+        private void OnStart()
+        {
+            communication = OpcUaClientOperate.Instance(BasicsData);
+            OperateResult operateResult = communication.On();
+            if (operateResult.State)
+            {
+                communication.OnEvent -= Communication_OnEvent;
+                communication.OnEvent += Communication_OnEvent;
+            }
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message.Replace("[", "[ ").Replace("]", " ] "));
+            if (e.RData != null && e.RData is ConcurrentDictionary<string, AddressValue>)
+            {
+                ConcurrentDictionary<string, AddressValue>? pairs = e.GetRData<ConcurrentDictionary<string, AddressValue>>();
+                if (pairs != null)
+                {
+                    foreach (var itemc in pairs)
+                    {
+                        Output($"{e.Message}  -  Key:{itemc.Key}  -  Value:{itemc.Value.Value}");
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 停止
+        /// </summary>
+        public ICommand Stop { get => new CommandX(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OnToggleButton_Unchecked(null);
+
+
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+
+        /// <summary>
+        /// 树节点集合
+        /// </summary>
+        public ObservableCollection<NodeStructuralBody> Node
+        {
+            get => GetProperty(() => Node);
+            set => SetProperty(() => Node, value);
+        }
+
+        /// <summary>
+        /// 树节点选中集合
+        /// </summary>
+        public NodeStructuralBody NodeSelectedItem
+        {
+            get => GetProperty(() => NodeSelectedItem);
+            set => SetProperty(() => NodeSelectedItem, value);
+        }
+
+        /// <summary>
+        /// 节点信息集合
+        /// </summary>
+        public ObservableCollection<NodeMessageStructuralBody> NodeMessage
+        {
+            get => GetProperty(() => NodeMessage);
+            set => SetProperty(() => NodeMessage, value);
+        }
+
+        /// <summary>
+        /// 选中的节点信息
+        /// </summary>
+        public NodeMessageStructuralBody NodeMessageSelectedItem
+        {
+            get => GetProperty(() => NodeMessageSelectedItem);
+            set => SetProperty(() => NodeMessageSelectedItem, value);
+        }
+
+        /// <summary>
+        /// 节点地址
+        /// </summary>
+        public string DotAddress
+        {
+            get => GetProperty(() => DotAddress);
+            set => SetProperty(() => DotAddress, value);
+        }
+
+        /// <summary>
+        /// 写入数据
+        /// </summary>
+        public string WriteInData
+        {
+            get => GetProperty(() => WriteInData);
+            set => SetProperty(() => WriteInData, value);
+        }
+
+        /// <summary>
+        /// 读取
+        /// </summary>
+        public ICommand Read { get => new CommandX(OnRead); }
+
+        /// <summary>
+        /// 订阅
+        /// </summary>
+        public ICommand Subscribe { get => new CommandX(OnSubscribe); }
+
+        /// <summary>
+        /// 写入
+        /// </summary>
+        public ICommand Write { get => new CommandX(OnWrite); }
+
+        /// <summary>
+        /// 取消订阅
+        /// </summary>
+        public ICommand UnSubscribe { get => new CommandX(OnUnSubscribe); }
+
+        /// <summary>
+        /// 树控件被选中
+        /// </summary>
+        public ICommand TreeView_SelectedItemChanged { get => new CommandX<System.Windows.RoutedPropertyChangedEventArgs<object>>(OnTreeView_SelectedItemChanged); }
+
+        /// <summary>
+        /// 表格列被选中
+        /// </summary>
+        public ICommand DataGrid_SelectedCellsChanged { get => new CommandX<object>(OnDataGrid_SelectedCellsChanged); }
+
+        /// <summary>
+        /// 鼠标右键在树控件按下
+        /// </summary>
+        public ICommand TreeView_PreviewMouseRightButtonDown { get => new CommandX<MouseButtonEventArgs>(OnTreeView_PreviewMouseRightButtonDown); }
+
+        public ICommand TreeViewItem_Expanded { get => new CommandX<RoutedEventArgs>(OnTreeViewItem_Expanded); }
+
+        /// <summary>
+        /// 批量订阅
+        /// </summary>
+        public ICommand ContextMenu_Subscribe { get => new CommandX<object>(OnContextMenu_Subscribe); }
+
+        /// <summary>
+        /// 取消批量订阅
+        /// </summary>
+        public ICommand ContextMenu_UnSubscribe { get => new CommandX<Object>(OnContextMenu_UnSubscribe); }
+
+        /// <summary>
+        /// 导出节点
+        /// </summary>
+        public ICommand ContextMenu_ExpNode { get => new CommandX<object>(OnContextMenu_ExpNode); }
+
+        #region 命令实现
+
+        /// <summary>
+        /// 右键菜单点击取消批量订阅
+        /// </summary>
+        /// <param name="e"></param>
+        public void OnContextMenu_UnSubscribe(object e)
+        {
+            if (NodeSelectedItem == null)
+            {
+                Output("请选中节点后操作");
+                return;
+            }
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>();
+            foreach (var item in SubscribeNodes(NodeSelectedItem))
+            {
+                address.AddressArray.Add(new AddressDetails()
+                {
+                    AddressName = item
+                });
+            }
+            //取消订阅
+            OperateResult operateResult = communication.RemoveSubscribe(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 右键菜单点击批量订阅
+        /// </summary>
+        /// <param name="e"></param>
+        public async void OnContextMenu_Subscribe(object e)
+        {
+            if (NodeSelectedItem == null)
+            {
+                Output("请选中节点后操作");
+                return;
+            }
+
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>();
+            foreach (var item in SubscribeNodes(NodeSelectedItem))
+            {
+                address.AddressArray.Add(new AddressDetails()
+                {
+                    AddressName = item
+                });
+            }
+
+            //订阅
+            OperateResult operateResult = communication.Subscribe(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        private List<NodeJsonStructuralBody> nodes;
+
+        private void ec(NodeJsonStructuralBody node)
+        {
+            if (nodes == null)
+            {
+                nodes = new List<NodeJsonStructuralBody>();
+            }
+            if (node.Nodes != null)
+            {
+                foreach (var item in node.Nodes)
+                {
+                    if (item.Nodes != null)
+                    {
+                        foreach (var no in item.Nodes)
+                        {
+                            ec(no);
+                        }
+                    }
+                    else
+                    {
+                        nodes.Add(item);
+                    }
+                }
+            }
+            else
+            {
+                nodes.Add(node);
+            }
+        }
+
+        /// <summary>
+        /// 导出节点
+        /// </summary>
+        /// <param name="e"></param>
+        public async void OnContextMenu_ExpNode(object e)
+        {
+            if (NodeSelectedItem == null)
+            {
+                Output("请选中节点后操作");
+                return;
+            }
+            string str = YSAI.Unility.Windows.FileTool.SelectFolder();
+            if (string.IsNullOrEmpty(str))
+            {
+                Output("取消节点导出,未选择存储路径");
+            }
+            else
+            {
+                NodeJsonStructuralBody nodeStructuralBody = await ExpNodes(NodeSelectedItem);
+                string Path = str + $"\\[{nodeStructuralBody.Name}]Node {DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";
+                //设置json序列化反序列化格式
+                JsonSerializerSettings JsonSetting = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };
+                //当有空数据时不做解析,且进行缩进处理
+                string Json = JsonConvert.SerializeObject(nodeStructuralBody, Newtonsoft.Json.Formatting.None, JsonSetting);
+                //写入文件
+                FileTool.StringToFile(Path, Json.JsonFormatting());
+
+                ec(nodeStructuralBody);//, str + $"\\[{nodeStructuralBody.Name}]Node_Address {DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json");
+
+                Address address = new Address();
+                address.AddressArray = new List<AddressDetails>();
+                foreach (var item in nodes)
+                {
+                    address.AddressArray.Add(new AddressDetails
+                    {
+                        AddressName = item.Address,
+                        AddressDescribe = item.Description,
+                        AddressDataType = communication.TypeConvert((BuiltInType)Enum.Parse(typeof(BuiltInType), item.DataType))
+                    });
+                }
+                Path = str + $"\\[{nodeStructuralBody.Name}]Node_Address {DateTime.Now.ToString("yyyyMMddHHmmssffff")}.json";
+                //写入文件
+                FileTool.StringToFile(Path, address.ToJson().JsonFormatting());
+
+                Output($"节点成功导出至:{Path}");
+            }
+        }
+
+        /// <summary>
+        /// 树控件让其选中
+        /// </summary>
+        /// <returns></returns>
+        private DependencyObject VisualUpwardSearch<T>(DependencyObject source)
+        {
+            while (source != null && source.GetType() != typeof(T))
+                source = VisualTreeHelper.GetParent(source);
+            return source;
+        }
+
+        /// <summary>
+        /// 项被展开
+        /// </summary>
+        private void OnTreeViewItem_Expanded(RoutedEventArgs e)
+        {
+            Console.WriteLine();
+        }
+
+        /// <summary>
+        /// 鼠标右键在树控件按下 让其选中
+        /// </summary>
+        /// <param name="e"></param>
+        public void OnTreeView_PreviewMouseRightButtonDown(MouseButtonEventArgs e)
+        {
+            TreeViewItem treeView = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
+            if (treeView == null)
+            {
+                NodeSelectedItem = null;
+            }
+            else
+            {
+                NodeSelectedItem = treeView.DataContext as NodeStructuralBody;
+            }
+        }
+
+        /// <summary>
+        /// 表格列被选中
+        /// </summary>
+        public void OnDataGrid_SelectedCellsChanged(object e)
+        {
+            if (NodeMessageSelectedItem?.Name == null)
+            {
+                return;
+            }
+            DotAddress = NodeMessageSelectedItem?.Address;
+        }
+
+        /// <summary>
+        /// 树控件被选中
+        /// </summary>
+        /// <param name="e"></param>
+        public void OnTreeView_SelectedItemChanged(System.Windows.RoutedPropertyChangedEventArgs<object> e)
+        {
+            //节点数据转换
+            NodeStructuralBody? node = e.NewValue as NodeStructuralBody;
+
+            if (node == null) return;
+
+            //节点地址赋值
+            DotAddress = (node.NodeID as ReferenceDescription).NodeId.ToString();
+
+            //实例化节点数据
+            List<NodeId> nodeIds = new List<NodeId>();
+
+            if (node.Children.Count > 0)  //读取节点下的数据
+            {
+                //汇总节点数据
+                foreach (var item in node.Children)
+                {
+                    nodeIds.Add((NodeId)(item.NodeID as ReferenceDescription).NodeId);
+                }
+            }
+            else   //读取当前节点数据
+            {
+                nodeIds.Add((NodeId)(node.NodeID as ReferenceDescription).NodeId);
+            }
+
+            DataValue[] dataValues = communication.DetailedReadAllNodeData(nodeIds);
+
+            if (dataValues != null)
+            {
+                ShowDetailedMessage(dataValues, nodeIds);
+            }
+        }
+        /// <summary>
+        /// 读取
+        /// </summary>
+        public void OnRead()
+        {
+            if (communication == null || !communication.IsConnected)
+            {
+                Output("尚未连接");
+                return;
+            }
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>()
+            {
+                new AddressDetails()
+                {
+                    AddressName = DotAddress
+                }
+            };
+
+            OperateResult operateResult = communication.Read(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 订阅
+        /// </summary>
+        public void OnSubscribe()
+        {
+            if (communication == null || !communication.IsConnected)
+            {
+                Output("尚未连接");
+                return;
+            }
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>()
+            {
+                new AddressDetails()
+                {
+                    AddressName = DotAddress
+                }
+            };
+            //订阅
+            OperateResult operateResult = communication.Subscribe(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 写入
+        /// </summary>
+        public void OnWrite()
+        {
+            if (communication == null || !communication.IsConnected)
+            {
+                Output("尚未连接");
+                return;
+            }
+            if (DotAddress.IsNullOrEmpty() || WriteInData.IsNullOrEmpty())
+            {
+                Output("节点与参数不能为空");
+                return;
+            }
+
+            ConcurrentDictionary<string, object> pairs = new ConcurrentDictionary<string, object>();
+            try
+            {
+                switch (DataType)
+                {
+                    case 0:  //string
+                        pairs.TryAdd(DotAddress, WriteInData);
+                        break;
+                    case 1:  //double
+                        pairs.TryAdd(DotAddress, double.Parse(WriteInData));
+                        break;
+                    case 2:  //float
+                        pairs.TryAdd(DotAddress, float.Parse(WriteInData));
+                        break;
+                    case 3:  //int
+                        pairs.TryAdd(DotAddress, int.Parse(WriteInData));
+                        break;
+                    case 4:  //bool
+                        pairs.TryAdd(DotAddress, bool.Parse(WriteInData));
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                Output($"数据格式不正确:{ex.Message}");
+                return;
+            }
+            //写入
+            OperateResult operateResult = communication.Write(pairs);
+            //信息输出
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 取消订阅
+        /// </summary>
+        public void OnUnSubscribe()
+        {
+            if (communication == null || !communication.IsConnected)
+            {
+                Output("尚未连接");
+                return;
+            }
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>()
+            {
+                new AddressDetails()
+                {
+                    AddressName = DotAddress
+                }
+            };
+            //取消订阅
+            OperateResult operateResult = communication.UnSubscribe(address);
+            //信息输出
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        #endregion 命令实现
+
+
+        /// <summary>
+        /// 获取所有节点
+        /// </summary>
+        private Task GetAllNode(CancellationTokenSource token)
+        {
+            return Task.Factory.StartNew(() =>
+            {
+                //获取所有节点
+                ReferenceDescriptionCollection references = communication.GetAllNode(communication.GetNodeID()).Result;
+                //获取成功
+                if (references != null)
+                {
+                    for (int ii = 0; ii < references.Count; ii++)
+                    {
+                        //赋值
+                        ReferenceDescription target = references[ii];
+                        //得到这个节点下有多少个节点
+                        ReferenceDescriptionCollection descriptions = communication.GetAllNode((NodeId)target.NodeId).Result;
+                        if (descriptions != null)
+                        {
+                            try
+                            {
+                                int references1 = descriptions.Count;
+
+                                DrawingImage drawingImage = null;
+
+                                string imagename = communication.GetNodeIconType(target, communication.GetNodeID());
+                                System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() => drawingImage = (DrawingImage)System.Windows.Application.Current.FindResource(imagename)));
+
+                                //赋值
+                                NodeStructuralBody structuralBody = new NodeStructuralBody() { Name = target.ToString(), Icon = drawingImage, NodeID = target, Count = references1 > 0 ? $"( {references1} )" : string.Empty };
+
+                                //看此节点下是否存在节点
+                                if (references1 > 0)
+                                {
+                                    GetBranchNode((NodeId)target.NodeId, structuralBody, token);
+                                }
+
+                                System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() => Node.Add(structuralBody)));
+                            }
+                            catch { }
+                        }
+                    }
+                }
+            }, token.Token);
+        }
+
+        /// <summary>
+        /// 获取分支
+        /// </summary>
+        private Task GetBranchNode(NodeId nodeId, NodeStructuralBody node, CancellationTokenSource token)
+        {
+            return Task.Factory.StartNew(() =>
+            {
+                System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() =>
+                {
+                    //清空空白项
+                    node.Children.Clear();
+                }));
+                //获取分支下所有节点
+                ReferenceDescriptionCollection references = communication.GetAllNode(nodeId).Result;
+
+                //获取成功
+                if (references != null && references.Count > 0)
+                {
+                    for (int ii = 0; ii < references.Count; ii++)
+                    {
+                        //赋值
+                        ReferenceDescription target = references[ii];
+                        //得到这个节点下有多少个节点
+                        ReferenceDescriptionCollection descriptions = communication.GetAllNode((NodeId)target.NodeId).Result;
+                        if (descriptions != null)
+                        {
+                            try
+                            {
+                                int references1 = descriptions.Count;
+
+                                DrawingImage drawingImage = null;
+
+                                string imagename = communication.GetNodeIconType(target, communication.GetNodeID());
+                                System.Windows.Application.Current?.Dispatcher.Invoke(new Action(async () => drawingImage = (DrawingImage)System.Windows.Application.Current.FindResource(imagename)));
+
+                                NodeStructuralBody structuralBody = new NodeStructuralBody() { Name = target.BrowseName.Name, Icon = drawingImage, NodeID = target, Count = references1 > 0 ? $"( {references1} )" : string.Empty };
+
+                                //看此节点下是否存在节点
+                                if (references1 > 0)
+                                {
+                                    //赋值
+                                    GetBranchNode((NodeId)target.NodeId, structuralBody, token);
+                                }
+                                System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() => node.Children.Add(structuralBody)));
+                            }
+                            catch { }
+                        }
+                    }
+                }
+            }, token.Token);
+        }
+
+        /// <summary>
+        /// object[] 分割
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="Segmentation">几位几位分割</param>
+        private List<object[]> Segmentation(object[] Data, int Segmentation)
+        {
+            List<object[]> bytels = new List<object[]>();
+            for (int i = 0; i < Data.Length; i += Segmentation)
+            {
+                object[] bytes = new object[Segmentation];
+                for (int ic = 0; ic < Segmentation; ic++)
+                {
+                    bytes[ic] = Data[i + ic];
+                }
+                bytels.Add(bytes);
+                if (bytels.Count.Equals(Data.Length / Segmentation)) break;
+            }
+            return bytels;
+        }
+
+        /// <summary>
+        /// 显示节点或节点下的详细数据
+        /// </summary>
+        private void ShowDetailedMessage(DataValue[] dataValues, List<NodeId> nodeIds)
+        {
+            //数据先分割
+            List<object[]> objects = Segmentation(dataValues, 5);
+            //实例化
+            if (NodeMessage == null)
+            {
+                NodeMessage = new ObservableCollection<NodeMessageStructuralBody>();
+            }
+            //清空历史数据
+            NodeMessage.Clear();
+
+            for (int i = 0; i < nodeIds.Count; i++)
+            {
+                //名称
+                string name = nodeIds[i].ToString().Split('=')[nodeIds[i].ToString().Split('=').Length - 1];
+                //地址
+                string address = nodeIds[i].ToString();
+                //值
+                string value = objects[i][1].ToString();
+                //类型
+                string type = (communication.GetNodeValueType(nodeIds[i])).ToString();
+                //描述
+                string des = objects[i][4].ToString();
+                //访问级别
+                string accessLevel = communication.GetAccessLevel((DataValue)objects[i][2]);
+
+                NodeMessage.Add(new NodeMessageStructuralBody() { AccessLevel = accessLevel, Name = name, Type = type, Value = value, Description = des, Address = address });
+            }
+        }
+
+        /// <summary>
+        /// 订阅节点  只获取节点的订阅
+        /// </summary>
+        /// <param name="node"></param>
+        private List<string> SubscribeNodes(NodeStructuralBody node, List<string> str = null)
+        {
+            if (str == null)
+            {
+                str = new List<string>();
+            }
+            if (node.Children.Count == 0)
+            {
+                str.Add((node.NodeID as ReferenceDescription).NodeId.ToString());
+            }
+            else
+            {
+                foreach (var item in node.Children)
+                {
+                    str.AddRange(SubscribeNodes(item, new List<string>()));
+                }
+            }
+            return str;
+        }
+
+        /// <summary>
+        /// 导出节点
+        /// </summary>
+        /// <param name="body"></param>
+        private async Task<NodeJsonStructuralBody> ExpNodes(NodeStructuralBody node, NodeJsonStructuralBody nodeJson = null)
+        {
+            if (nodeJson == null)
+            {
+                nodeJson = new NodeJsonStructuralBody();
+            }
+
+            List<NodeId> nodeIds = new List<NodeId>();
+            nodeIds.Add((NodeId)(node.NodeID as ReferenceDescription).NodeId);
+            DataValue[] dataValues = communication.DetailedReadAllNodeData(nodeIds);  //获取此节点信息
+
+            nodeJson.DataType = (communication.GetNodeValueType((NodeId)(node.NodeID as ReferenceDescription).NodeId)).ToString();
+            nodeJson.Name = dataValues[3].ToString();
+            nodeJson.Description = dataValues[4].ToString();
+            if (node.Children.Count > 0)  //父级
+            {
+                if (nodeJson.Nodes == null)
+                {
+                    nodeJson.Nodes = new List<NodeJsonStructuralBody>();
+                }
+                foreach (var item in node.Children)
+                {
+                    nodeJson.Nodes.Add(await ExpNodes(item, new NodeJsonStructuralBody()));
+                }
+            }
+            else
+            {
+                nodeJson.Address = (node.NodeID as ReferenceDescription).NodeId.ToString();
+                nodeJson.Name = nodeJson.Address.Split('=')[nodeJson.Address.Split('=').Length - 1];
+            }
+            return nodeJson;
+        }
+
+
+
+    }
+}
+

+ 9 - 0
src/YSAI.Tool.Wpf/controllers/UdpController.cs

@@ -195,6 +195,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
         /// <summary>

+ 9 - 0
src/YSAI.Tool.Wpf/controllers/WsClientController.cs

@@ -184,6 +184,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
 

+ 13 - 28
src/YSAI.Tool.Wpf/controllers/WsServiceController.cs

@@ -189,6 +189,15 @@ namespace YSAI.Tool.Wpf.controllers
             Info = string.Empty;
         }
 
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
         #endregion 统一需要的数据
 
 
@@ -382,40 +391,16 @@ namespace YSAI.Tool.Wpf.controllers
             {
                 public string IP
                 {
-                    get
-                    {
-                        return ip;
-                    }
-                    set
-                    {
-                        if (value != null && !value.Equals(ip))
-                        {
-                            ip = value;
-                            RaisePropertyChanged("IP");
-                        }
-                    }
+                    get => GetProperty(() => IP);
+                    set => SetProperty(() => IP, value);
                 }
 
-                private string ip;
-
                 public string Port
                 {
-                    get
-                    {
-                        return port;
-                    }
-                    set
-                    {
-                        if (value != null && !value.Equals(port))
-                        {
-                            port = value;
-                            RaisePropertyChanged("Port");
-                        }
-                    }
+                    get => GetProperty(() => Port);
+                    set => SetProperty(() => Port, value);
                 }
 
-                private string port;
-
                 /// <summary>
                 /// 地址与端口
                 /// </summary>

+ 66 - 0
src/YSAI.Tool.Wpf/data/NodeMessageStructuralBody.cs

@@ -0,0 +1,66 @@
+
+
+using YSAI.Core.Wpf.mvvm;
+
+namespace YSAI.Tool.Wpf.data
+{
+    /// <summary>
+    /// 节点信息结构体
+    /// </summary>
+    public class NodeMessageStructuralBody : NotifyObject
+    {
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string Name
+        {
+            get => GetProperty(() => Name);
+            set => SetProperty(() => Name, value);
+        }
+
+        /// <summary>
+        /// 地址
+        /// </summary>
+        public string Address
+        {
+            get => GetProperty(() => Address);
+            set => SetProperty(() => Address, value);
+        }
+
+        /// <summary>
+        /// 值
+        /// </summary>
+        public string Value
+        {
+            get => GetProperty(() => Value);
+            set => SetProperty(() => Value, value);
+        }
+
+        /// <summary>
+        /// 类型
+        /// </summary>
+        public string Type
+        {
+            get => GetProperty(() => Type);
+            set => SetProperty(() => Type, value);
+        }
+
+        /// <summary>
+        /// 访问级别
+        /// </summary>
+        public string AccessLevel
+        {
+            get => GetProperty(() => AccessLevel);
+            set => SetProperty(() => AccessLevel, value);
+        }
+
+        /// <summary>
+        /// 描述
+        /// </summary>
+        public string Description
+        {
+            get => GetProperty(() => Description);
+            set => SetProperty(() => Description, value);
+        }
+    }
+}

+ 58 - 0
src/YSAI.Tool.Wpf/data/NodeStructuralBody.cs

@@ -0,0 +1,58 @@
+using System.Collections.ObjectModel;
+using YSAI.Core.Wpf.mvvm;
+
+namespace YSAI.Tool.Wpf.data
+{
+    /// <summary>
+    /// 节点信息
+    /// </summary>
+    public class NodeStructuralBody : NotifyObject
+    {
+        /// <summary>
+        /// 节点图片
+        /// </summary>
+        public object Icon
+        {
+            get => GetProperty(() => Icon);
+            set => SetProperty(() => Icon, value);
+        }
+
+        /// <summary>
+        /// 节点名称
+        /// </summary>
+        public string Name
+        {
+            get => GetProperty(() => Name);
+            set => SetProperty(() => Name, value);
+        }
+
+        /// <summary>
+        /// 节点对象
+        /// </summary>
+        public object NodeID
+        {
+            get => GetProperty(() => NodeID);
+            set => SetProperty(() => NodeID, value);
+        }
+
+        /// <summary>
+        /// 数量
+        /// </summary>
+        public string Count
+        {
+            get => GetProperty(() => Count);
+            set => SetProperty(() => Count, value);
+        }
+
+        public ObservableCollection<NodeStructuralBody> Children
+        {
+            get => GetProperty(() => Children);
+            set => SetProperty(() => Children, value);
+        }
+
+        public NodeStructuralBody()
+        {
+            Children = new ObservableCollection<NodeStructuralBody>();
+        }
+    }
+}

+ 63 - 26
src/YSAI.Tool.Wpf/views/Serial.xaml

@@ -71,43 +71,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -118,7 +120,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -166,14 +168,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 63 - 26
src/YSAI.Tool.Wpf/views/TcpClient.xaml

@@ -69,43 +69,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -116,7 +118,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -164,14 +166,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 63 - 26
src/YSAI.Tool.Wpf/views/TcpService.xaml

@@ -69,43 +69,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -116,7 +118,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -164,14 +166,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 602 - 0
src/YSAI.Tool.Wpf/views/UaClient.xaml

@@ -0,0 +1,602 @@
+<UserControl x:Class="YSAI.Tool.Wpf.views.UaClient"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:YSAI.Tool.Wpf.views"
+             xmlns:NodeStructuralBody="clr-namespace:YSAI.Tool.Wpf.data"
+             
+             xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+             xmlns:txt="clr-namespace:YSAI.Core.Wpf.controls.textbox;assembly=YSAI.Core.Wpf"
+             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+             xmlns:pt="http://propertytools.org/wpf"
+             xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+             Background="{DynamicResource ContentBackgroundPicture}">
+    <UserControl.DataContext>
+        <c:UaClientController />
+    </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DatePicker.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeView.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                    <ColumnDefinition Width="auto"/>
+                </Grid.ColumnDefinitions>
+
+                <ToggleButton Grid.Column="0"  Grid.ColumnSpan="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,-28,3,0" ToolTip="节点信息浏览[隐藏/显示]" Panel.ZIndex="3">
+                    <i:Interaction.Triggers>
+                        <i:EventTrigger EventName="Unchecked">
+                            <mvvm:EventCommand  Command="{Binding ToggleButton_Unchecked}" />
+                        </i:EventTrigger>
+                        <i:EventTrigger EventName="Checked">
+                            <mvvm:EventCommand  Command="{Binding ToggleButton_Checked}" />
+                        </i:EventTrigger>
+                    </i:Interaction.Triggers>
+                    <ToggleButton.Template>
+                        <ControlTemplate TargetType="{x:Type ToggleButton}">
+                            <Image x:Name="image" Source="{DynamicResource ZommOff}" Stretch="Fill" Width="15" Height="15" />
+                            <ControlTemplate.Triggers>
+                                <Trigger Property="IsChecked" Value="True">
+                                    <Setter Property="Source" TargetName="image" Value="{DynamicResource ZommOn}"/>
+                                </Trigger>
+                            </ControlTemplate.Triggers>
+                        </ControlTemplate>
+                    </ToggleButton.Template>
+                    <ToggleButton.Triggers>
+                        <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                            <BeginStoryboard>
+                                <Storyboard>
+                                    <DoubleAnimation Storyboard.TargetName="nodeBrowse" Storyboard.TargetProperty="MinWidth" From="1150" To="0" Duration="0:0:0.7"/>
+                                </Storyboard>
+                            </BeginStoryboard>
+                        </EventTrigger>
+                        <EventTrigger RoutedEvent="ToggleButton.Checked">
+                            <BeginStoryboard>
+                                <Storyboard>
+                                    <DoubleAnimation Storyboard.TargetName="nodeBrowse" Storyboard.TargetProperty="MinWidth" From="0" To="1150" Duration="0:0:0.7"/>
+                                </Storyboard>
+                            </BeginStoryboard>
+                        </EventTrigger>
+                    </ToggleButton.Triggers>
+                </ToggleButton>
+                <!--基础数据-->
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="auto"/>
+                    </Grid.RowDefinitions>
+
+                    <!--导入导出-->
+                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
+                    </StackPanel>
+                    <!--属性表格-->
+                    <Grid Grid.Row="1" Panel.ZIndex="1">
+                        <Grid.Resources>
+                            <ResourceDictionary>
+                                <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="HorizontalAlignment" Value="Left"/>
+                                </Style>
+                                <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource DefaultComboBox}" >
+                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="Background" Value="White"/>
+                                    <Setter Property="VerticalAlignment" Value="Center"/>
+                                    <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
+                                </Style>
+                                <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" >
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <ToggleButton Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid Grid.Row="0" Grid.Column="1"  Margin="0,-40,0,0">
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
+                                    <btn:ButtonControl  Grid.Column="5"  Width="80"   Command="{Binding Start}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                                        IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                        BorderBrush="{DynamicResource Control.Border.Color}"
+                                                        IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                        Foreground="{DynamicResource Font.Content.Foreground}"
+                                                        Icon="{DynamicResource ConnectBase}"
+                                                        Content="连接"/>
+
+                                    <btn:ButtonControl  Grid.Column="6"  Width="80"  Command="{Binding Stop}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                                        IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                        BorderBrush="{DynamicResource Control.Border.Color}"
+                                                        IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                        Foreground="{DynamicResource Font.Content.Foreground}"
+                                                        Icon="{DynamicResource OffConnect}"
+                                                        Content="断开"/>
+                                </StackPanel>
+                            </Grid>
+                            <!--发送区域-->
+                            <Grid Grid.Row="1" Grid.Column="1">
+                                <Grid Margin="7">
+                                    <Grid.RowDefinitions>
+                                        <RowDefinition/>
+                                        <RowDefinition/>
+                                        <RowDefinition/>
+                                    </Grid.RowDefinitions>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition/>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition  Width="auto"/>
+                                    </Grid.ColumnDefinitions>
+
+                                    <GroupBox Grid.ColumnSpan="3"  Style="{StaticResource GroupBoxTab}" Margin="0,1,0,10">
+                                        <GroupBox.Header>
+                                            <StackPanel Orientation="Horizontal">
+                                                <Grid Background="transparent">
+                                                    <Grid.ColumnDefinitions>
+                                                        <ColumnDefinition Width="auto" />
+                                                        <ColumnDefinition Width="*" />
+                                                    </Grid.ColumnDefinitions>
+                                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource DataType}" Width="14" />
+                                                    <TextBlock Text="数据类型" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                                </Grid>
+                                            </StackPanel>
+                                        </GroupBox.Header>
+                                        <Grid Margin="7">
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition/>
+                                                <ColumnDefinition/>
+                                                <ColumnDefinition/>
+                                                <ColumnDefinition/>
+                                                <ColumnDefinition/>
+                                            </Grid.ColumnDefinitions>
+                                            <RadioButton Grid.Column="0" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="String" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="1" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Double"  VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="2" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="Float" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="3" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Int"  VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="4" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="Bool" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                        </Grid>
+                                    </GroupBox>
+
+                                    <txt:TextBoxControl Grid.Column="0" Grid.Row="1" FontSize="13" HorizontalContentAlignment="Center" Text="{Binding DotAddress}"
+                                                              SelectedColor="{DynamicResource Control.Border.Two.Color}"
+                                                              BorderBrush="{DynamicResource Control.Border.Color}"
+                                                              Foreground="{DynamicResource Font.Content.Foreground}"
+                                                              Icon="{DynamicResource Dot}"
+                                                              HintColor="{DynamicResource Control.Border.One.Color}"
+                                                              ShowIcon="True"
+                                                              Hint="节点地址"
+                                                              CornerRadius="{DynamicResource WindowCornerRadius}" />
+
+                                    <txt:TextBoxControl Grid.Column="0" Grid.Row="2" Margin="0,10,0,0" FontSize="13" HorizontalContentAlignment="Center" VerticalAlignment="Center" Text="{Binding WriteInData}"
+                                                             SelectedColor="{DynamicResource Control.Border.Two.Color}"
+                                                             BorderBrush="{DynamicResource Control.Border.Color}"
+                                                             Foreground="{DynamicResource Font.Content.Foreground}"
+                                                             Icon="{DynamicResource WriteIn}"
+                                                             HintColor="{DynamicResource Control.Border.One.Color}"
+                                                             ShowIcon="True"
+                                                             Hint="写入数据"
+                                                             CornerRadius="{DynamicResource WindowCornerRadius}" />
+
+                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="1" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
+                                                              IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                              BorderBrush="{DynamicResource Control.Border.Color}"
+                                                              IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                              Foreground="{DynamicResource Font.Content.Foreground}"
+                                                              Icon="{DynamicResource Read}"
+                                                              Content="读取"/>
+
+                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="1" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
+                                                              IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                              BorderBrush="{DynamicResource Control.Border.Color}"
+                                                              IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                              Foreground="{DynamicResource Font.Content.Foreground}"
+                                                              Icon="{DynamicResource Write}"
+                                                              Content="写入"/>
+
+                                    <btn:ButtonControl  Width="100" Grid.Row="1" Grid.Column="2" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"  CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,0,0,0"
+                                                                IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                                BorderBrush="{DynamicResource Control.Border.Color}"
+                                                                IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                                Foreground="{DynamicResource Font.Content.Foreground}"
+                                                                Icon="{DynamicResource Subscribe}"
+                                                                Content="订阅"/>
+
+                                    <btn:ButtonControl  Width="100" Grid.Row="2" Grid.Column="2" Command="{Binding Start}" HorizontalAlignment="Center" VerticalAlignment="Center"   CornerRadius="{DynamicResource WindowCornerRadius}"  Margin="10,10,0,0"
+                                                                IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                                BorderBrush="{DynamicResource Control.Border.Color}"
+                                                                IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                                Foreground="{DynamicResource Font.Content.Foreground}"
+                                                                Icon="{DynamicResource UnSubscribe}"
+                                                                Content="取消订阅"/>
+
+                                </Grid>
+                            </Grid>
+                        </Grid>
+
+
+
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+                    </GroupBox>
+                    <!--信息-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,5,0,0"  Grid.Row="1">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Info}" Width="14" />
+                                    <TextBlock Text="信息" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition />
+                            </Grid.RowDefinitions>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,-40,0,0">
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <btn:ButtonControl  Width="80"  Command="{Binding Clear}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+Foreground="{DynamicResource Font.Content.Foreground}"
+Icon="{DynamicResource Clear}"
+Content="清空"/>
+                            </StackPanel>
+                            <TextBox Grid.Row="1" Padding="5" Grid.ColumnSpan="2" Style="{DynamicResource TextBoxStyle2}"  FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"  Text="{Binding Info}" >
+                                <i:Interaction.Triggers>
+                                    <i:EventTrigger EventName="TextChanged">
+                                        <mvvm:EventCommand  Command="{Binding Info_TextChanged}" />
+                                    </i:EventTrigger>
+                                </i:Interaction.Triggers>
+                            </TextBox>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
+
+
+
+
+                <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+                <!--节点浏览-->
+                <Grid Grid.Column="2"  Width="0" x:Name="nodeBrowse">
+                    <GroupBox Style="{StaticResource GroupBoxTab}"  Margin="4,0,0,0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Menu}" Width="14" />
+                                    <TextBlock Text="节点信息浏览" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition Width="260" />
+                                <ColumnDefinition />
+                            </Grid.ColumnDefinitions>
+                            <!--节点-->
+                            <Grid Grid.Column="0">
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,0,5,0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid Background="transparent">
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto" />
+                                                    <ColumnDefinition Width="*" />
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource DotBase}" Width="14" />
+                                                <TextBlock Text="节点" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+                                    <TreeView  Background="Transparent" Margin="5,5,0,5"  BorderBrush="{DynamicResource Control.Border.Color}" ItemsSource="{Binding Node}" Style="{StaticResource TreeViewStyle}" >
+                                        <!--右键菜单-->
+                                        <TreeView.ContextMenu>
+                                            <ContextMenu VerticalContentAlignment="Center" FontSize="13">
+                                                <MenuItem Header="批量订阅" Foreground="{DynamicResource Font.Content.Foreground}">
+                                                    <i:Interaction.Triggers>
+                                                        <i:EventTrigger EventName="Click">
+                                                            <mvvm:EventCommand  Command="{Binding ContextMenu_Subscribe}" />
+                                                        </i:EventTrigger>
+                                                    </i:Interaction.Triggers>
+                                                    <MenuItem.Icon>
+                                                        <StackPanel Orientation="Horizontal">
+                                                            <Image Source="{DynamicResource Subscribe}"  Width="15" Height="15" VerticalAlignment="Center" />
+                                                        </StackPanel>
+                                                    </MenuItem.Icon>
+                                                </MenuItem>
+                                                <MenuItem Header="取消批量订阅" Foreground="{DynamicResource Font.Content.Foreground}">
+                                                    <i:Interaction.Triggers>
+                                                        <i:EventTrigger EventName="Click">
+                                                            <mvvm:EventCommand  Command="{Binding ContextMenu_UnSubscribe}" />
+                                                        </i:EventTrigger>
+                                                    </i:Interaction.Triggers>
+                                                    <MenuItem.Icon>
+                                                        <StackPanel Orientation="Horizontal">
+                                                            <Image Source="{DynamicResource UnSubscribe}"  Width="15" Height="15" VerticalAlignment="Center" />
+                                                        </StackPanel>
+                                                    </MenuItem.Icon>
+                                                </MenuItem>
+                                                <MenuItem Header="导出节点" Foreground="{DynamicResource Font.Content.Foreground}">
+                                                    <i:Interaction.Triggers>
+                                                        <i:EventTrigger EventName="Click">
+                                                            <mvvm:EventCommand  Command="{Binding ContextMenu_ExpNode}" />
+                                                        </i:EventTrigger>
+                                                    </i:Interaction.Triggers>
+                                                    <MenuItem.Icon>
+                                                        <StackPanel Orientation="Horizontal">
+                                                            <Image Source="{DynamicResource Exp}"  Width="15" Height="15" VerticalAlignment="Center" />
+                                                        </StackPanel>
+                                                    </MenuItem.Icon>
+                                                </MenuItem>
+                                            </ContextMenu>
+                                        </TreeView.ContextMenu>
+                                        <i:Interaction.Triggers>
+                                            <!--选中-->
+                                            <i:EventTrigger EventName="SelectedItemChanged">
+                                                <mvvm:EventCommand  Command="{Binding TreeView_SelectedItemChanged}" />
+                                            </i:EventTrigger>
+                                            <!--右键按下-->
+                                            <i:EventTrigger EventName="PreviewMouseRightButtonDown">
+                                                <mvvm:EventCommand  Command="{Binding TreeView_PreviewMouseRightButtonDown}" />
+                                            </i:EventTrigger>
+                                            <!--项被展开-->
+                                            <i:EventTrigger SourceName="TreeViewItem" EventName="Expanded">
+                                                <mvvm:EventCommand  Command="{Binding TreeViewItem_Expanded}" />
+                                            </i:EventTrigger>
+                                        </i:Interaction.Triggers>
+                                        <TreeView.ItemTemplate>
+                                            <HierarchicalDataTemplate  DataType="{x:Type NodeStructuralBody:NodeStructuralBody}" ItemsSource="{Binding Children}">
+                                                <StackPanel  Margin="0,5,0,5">
+                                                    <Grid>
+                                                        <Grid.ColumnDefinitions>
+                                                            <ColumnDefinition />
+                                                            <ColumnDefinition />
+                                                            <ColumnDefinition />
+                                                        </Grid.ColumnDefinitions>
+                                                        <Image VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Fill"  Source="{Binding Icon}" Width="11" Height="11" Margin="0,0,5,0" Grid.Column="0" />
+                                                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Name}" FontSize="13"   Foreground="{DynamicResource Font.Content.Foreground}" Grid.Column="1" Margin="0,0,5,0" />
+                                                        <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Count}" FontSize="11" Foreground="{DynamicResource Font.Content.Foreground}" Grid.Column="2" />
+                                                    </Grid>
+                                                </StackPanel>
+                                            </HierarchicalDataTemplate>
+                                        </TreeView.ItemTemplate>
+                                    </TreeView>
+                                </GroupBox>
+                            </Grid>
+                            <!--信息-->
+                            <Grid Grid.Column="1">
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid Background="transparent">
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto" />
+                                                    <ColumnDefinition Width="*" />
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Default}" Width="14" />
+                                                <TextBlock Text="详情" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+
+                                    <DataGrid ColumnHeaderHeight="40" ItemsSource="{Binding NodeMessage}" Grid.Row="0" FontSize="13" SelectedItem="{Binding NodeMessageSelectedItem}" BorderThickness="0">
+                                        <!--双击-->
+                                        <i:Interaction.Triggers>
+                                            <i:EventTrigger EventName="SelectedCellsChanged">
+                                                <mvvm:EventCommand  Command="{Binding DataGrid_SelectedCellsChanged}" />
+                                            </i:EventTrigger>
+                                        </i:Interaction.Triggers>
+                                        <DataGrid.Columns>
+                                            <DataGridTextColumn Header="名称"  Width="auto"  Binding="{Binding Name}" Visibility="Collapsed" />
+                                            <DataGridTextColumn Header="地址"  Width="*"  Binding="{Binding Address}" />
+                                            <DataGridTextColumn Header="值"  Width="150"  Binding="{Binding Value}" />
+                                            <DataGridTextColumn Header="类型" Width="120" Binding="{Binding Type}" />
+                                            <DataGridTextColumn Header="访问级别"  Width="150"  Binding="{Binding AccessLevel}" />
+                                            <DataGridTextColumn Header="描述"  Width="100"  Binding="{Binding Description}" />
+                                        </DataGrid.Columns>
+                                    </DataGrid>
+                                </GroupBox>
+                            </Grid>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
+
+
+                <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+            </Grid>
+        </GroupBox>
+    </Border>
+</UserControl>
+

+ 15 - 0
src/YSAI.Tool.Wpf/views/UaClient.xaml.cs

@@ -0,0 +1,15 @@
+using System.Windows.Controls;
+
+namespace YSAI.Tool.Wpf.views
+{
+    /// <summary>
+    /// UaClient.xaml 的交互逻辑
+    /// </summary>
+    public partial class UaClient : UserControl
+    {
+        public UaClient()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 63 - 26
src/YSAI.Tool.Wpf/views/Udp.xaml

@@ -69,43 +69,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -116,7 +118,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -164,14 +166,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}"> 
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 63 - 26
src/YSAI.Tool.Wpf/views/WsClient.xaml

@@ -64,43 +64,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,5,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -111,7 +113,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -159,14 +161,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 63 - 26
src/YSAI.Tool.Wpf/views/WsService.xaml

@@ -65,43 +65,45 @@
                     <ColumnDefinition Width="*"/>
                 </Grid.ColumnDefinitions>
                 <!--基础数据-->
-                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="auto"/>
                     </Grid.RowDefinitions>
+
                     <!--导入导出-->
                     <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding IncBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Inc}"
-                  Content="导入"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
                         <btn:ButtonControl  
-                  Width="80"
-                  Command="{Binding ExpBasics}" 
-                  HorizontalAlignment="Center" 
-                  VerticalAlignment="Center" 
-                  IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                  BorderBrush="{DynamicResource Control.Border.Color}"
-                  IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                  Foreground="{DynamicResource Font.Content.Foreground}"
-                  Icon="{DynamicResource Exp}"
-                  Content="导出"
-                  BorderThickness="1,0,0,0" />
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
                     </StackPanel>
                     <!--属性表格-->
                     <Grid Grid.Row="1" Panel.ZIndex="1">
                         <Grid.Resources>
                             <ResourceDictionary>
                                 <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="HorizontalAlignment" Value="Left"/>
                                 </Style>
@@ -112,7 +114,7 @@
                                     <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
                                 </Style>
                                 <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
-                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="FontSize" Value="13"/>
                                     <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
                                     <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
                                     <Setter Property="HorizontalContentAlignment" Value="Center"/>
@@ -160,14 +162,49 @@ CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
                     </Grid>
                 </Grid>
 
-
-
                 <!--功能模块与信息-->
                 <Grid Grid.Column="1" MinWidth="600">
                     <Grid.RowDefinitions>
                         <RowDefinition Height="auto"/>
                         <RowDefinition Height="*"/>
                     </Grid.RowDefinitions>
+
+                    <ToggleButton Grid.Row="0"  Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
                     <!--功能模块-->
                     <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
                         <GroupBox.Header>

+ 94 - 14
src/YSAI.Tool.Wpf/views/WsService.xaml.cs

@@ -1,18 +1,7 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
+using System.Windows.Controls;
 using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
+using YSAI.Core.Wpf;
+using YSAI.Unility.Windows;
 namespace YSAI.Tool.Wpf.views
 {
     /// <summary>
@@ -23,6 +12,97 @@ namespace YSAI.Tool.Wpf.views
         public WsService()
         {
             InitializeComponent();
+
+            Task.Run(() =>
+            {
+                //PropertyGrid 处理属性自动加载表格的 DataGrid样式修改
+                Thread.Sleep(50);
+                PropertyGridUpdate(true);
+            });
+
+            //当皮肤切换触发事件
+            WindowHelper.OnSkinSwitchEvent += WindowHelper_OnSkinSwitchEvent;
+        }
+
+
+        /// <summary>
+        /// PropertyGrid 处理属性自动加载表格的 DataGrid样式修改
+        /// </summary>
+        private void PropertyGridUpdate(bool init = false)
+        {
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (init)
+                {
+                    List<Grid> grids = this.FindVisualChild<Grid>();
+                    if (grids.Count > 0)
+                    {
+                        //选中的边框颜色
+                        Grid? grid = grids.FirstOrDefault(c => c.Name.Equals("PART_Grid"));
+                        if (grid != null)
+                        {
+                            grid.Background = new SolidColorBrush(Colors.Transparent);
+                        }
+                    }
+                }
+
+                Border? border = null;
+                List<Border> borders = this.FindVisualChild<Border>();
+                if (borders.Count > 0)
+                {
+                    //选中的边框颜色
+                    border = borders.FirstOrDefault(c => c.Name.Equals("PART_Selection"));
+                    if (border != null)
+                    {
+                        border.BorderBrush = (SolidColorBrush)this.FindResource("Control.Border.One.Color");
+                        if (init)
+                        {
+                            border.BorderThickness = new System.Windows.Thickness(1);
+                            border.Margin = new System.Windows.Thickness(0);
+                        }
+                    }
+
+                    //全部选中的边框颜色
+                    border = borders.FirstOrDefault(c => c.Name.Equals("PART_AutoFillSelection"));
+                    if (border != null)
+                    {
+                        border.BorderBrush = (SolidColorBrush)this.FindResource("Control.Border.Two.Color");
+                        if (init)
+                        {
+                            border.BorderThickness = new System.Windows.Thickness(1);
+                            border.Margin = new System.Windows.Thickness(0);
+                        }
+                    }
+                    if (init)
+                    {
+                        foreach (var item in new List<string>()
+                        {
+                            "PART_RowSelectionBackground",   //行选中背景色
+                            "PART_ColumnSelectionBackground",  //列选中背景色
+                            "PART_ColumnGrid",   //列背景色
+                            "PART_RowGrid",  //行背景色
+                            "PART_TopLeft",  //左上背景色
+                        })
+                        {
+                            border = borders.FirstOrDefault(c => c.Name.Equals(item));
+                            if (border != null)
+                            {
+                                border.Background = new SolidColorBrush(Colors.Transparent);
+                            }
+                        }
+                    }
+                }
+            });
+        }
+
+        /// <summary>
+        /// 皮肤发生变化
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void WindowHelper_OnSkinSwitchEvent(object? sender, System.EventArgs e)
+        {
+            PropertyGridUpdate();
         }
     }
 }

+ 48 - 0
src/YSAI.Unility.Windows/WpfHelperTool.cs

@@ -0,0 +1,48 @@
+using System.Windows;
+using System.Windows.Media;
+
+namespace YSAI.Unility.Windows
+{
+    public static class WpfHelperTool
+    {
+        /// <summary>
+        /// 检索模版下指定控件集
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="obj"></param>
+        /// <returns></returns>
+        public static List<T> FindVisualChild<T>(this DependencyObject obj) where T : DependencyObject
+        {
+            try
+            {
+                List<T> TList = new List<T> { };
+                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
+                {
+                    DependencyObject child = VisualTreeHelper.GetChild(obj, i);
+                    if (child != null && child is T)
+                    {
+                        TList.Add((T)child);
+                        List<T> childOfChildren = FindVisualChild<T>(child);
+                        if (childOfChildren != null)
+                        {
+                            TList.AddRange(childOfChildren);
+                        }
+                    }
+                    else
+                    {
+                        List<T> childOfChildren = FindVisualChild<T>(child);
+                        if (childOfChildren != null)
+                        {
+                            TList.AddRange(childOfChildren);
+                        }
+                    }
+                }
+                return TList;
+            }
+            catch (Exception ex)
+            {
+                return null;
+            }
+        }
+    }
+}