Przeglądaj źródła

依赖库更新

Shun 2 lat temu
rodzic
commit
7dbaa9ea91

+ 2 - 2
src/YSAI.AllenBradley/YSAI.AllenBradley.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -16,6 +16,6 @@
     <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Beckhoff/YSAI.Beckhoff.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -17,6 +17,6 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="Beckhoff.TwinCAT.Ads" Version="6.1.154" />
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Can/YSAI.Can.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -16,7 +16,7 @@
     <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Kvaser.CanLib">

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

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7484</Version>
+    <Version>23.360.5156</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>

+ 1 - 1
src/YSAI.DAQ.Samples/YSAI.DAQ.Samples.csproj

@@ -99,7 +99,7 @@
 
   <ItemGroup>
     <PackageReference Include="YSAI.Mqtt" Version="23.359.7955" />
-    <PackageReference Include="YSAI.Opc" Version="23.359.8686" />
+    <PackageReference Include="YSAI.Opc" Version="23.360.5691" />
   </ItemGroup>
 
   <ItemGroup>

+ 2 - 2
src/YSAI.DB/YSAI.DB.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -21,6 +21,6 @@
     <PackageReference Include="System.Data.OracleClient" Version="1.0.8" />
     <PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
     <PackageReference Include="System.Data.SQLite" Version="1.0.118" />
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Mewtocol/YSAI.Mewtocol.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -17,6 +17,6 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="Mewtocol.NET" Version="0.8.1" />
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Mitsubishi/YSAI.Mitsubishi.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -16,6 +16,6 @@
     <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Modbus/YSAI.Modbus.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -18,6 +18,6 @@
   <ItemGroup>
     <PackageReference Include="NModbus" Version="3.0.81" />
     <PackageReference Include="NModbus.Serial" Version="3.0.81" />
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Omron/YSAI.Omron.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -16,6 +16,6 @@
     <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
   </PropertyGroup>
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 5
src/YSAI.Opc/YSAI.Opc.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.359.8686</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -17,9 +17,6 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.106" />
-    <!--<PackageReference Include="YSAI.Core" Version="23.353.7484" />-->
-  </ItemGroup>
-  <ItemGroup>
-    <ProjectReference Include="..\YSAI.Core\YSAI.Core.csproj" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.Siemens/YSAI.Siemens.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.353.7802</Version>
+    <Version>23.360.5691</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>
@@ -17,6 +17,6 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="S7netplus" Version="0.20.0" />
-    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
+    <PackageReference Include="YSAI.Core" Version="23.360.5156" />
   </ItemGroup>
 </Project>

+ 9 - 10
src/YSAI.Tool.Wpf/YSAI.Tool.Wpf.csproj

@@ -17,25 +17,24 @@
 		<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.Beckhoff" Version="23.353.7802" />
-		<PackageReference Include="YSAI.DB" Version="23.353.7802" />
+		<PackageReference Include="YSAI.AllenBradley" Version="23.360.5691" />
+		<PackageReference Include="YSAI.Beckhoff" Version="23.360.5691" />
+		<PackageReference Include="YSAI.DB" Version="23.360.5691" />
 		<PackageReference Include="YSAI.Kafka" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Mewtocol" Version="23.353.7802" />
-		<PackageReference Include="YSAI.Mitsubishi" Version="23.353.7802" />
-		<PackageReference Include="YSAI.Modbus" Version="23.353.7802" />
+		<PackageReference Include="YSAI.Mewtocol" Version="23.360.5691" />
+		<PackageReference Include="YSAI.Mitsubishi" Version="23.360.5691" />
+		<PackageReference Include="YSAI.Modbus" Version="23.360.5691" />
 		<PackageReference Include="YSAI.Mqtt" Version="23.359.7955" />
 		<PackageReference Include="YSAI.NetMQ" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Netty" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Omron" Version="23.353.7802" />
-		<PackageReference Include="YSAI.Opc" Version="23.359.8686" />
+		<PackageReference Include="YSAI.Omron" Version="23.360.5691" />
+		<PackageReference Include="YSAI.Opc" Version="23.360.5691" />
 		<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.360.5691" />
 	</ItemGroup>
 	<ItemGroup>
 		<ProjectReference Include="..\YSAI.Core.Wpf\YSAI.Core.Wpf.csproj" />
-		<ProjectReference Include="..\YSAI.Opc\YSAI.Opc.csproj" />
 	</ItemGroup>
 
 	<ItemGroup>

+ 930 - 0
src/YSAI.Tool.Wpf/controllers/DaClientController.cs

@@ -0,0 +1,930 @@
+using CommunityToolkit.Mvvm.Input;
+using System.Collections.Concurrent;
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using YSAI.Core.Wpf;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Opc.da.client;
+using YSAI.Unility;
+using static YSAI.Opc.da.client.OpcDaClientData;
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class DaClientController : NotifyObject
+    {
+        public DaClientController()
+        {
+            //当皮肤切换触发事件
+            WindowHelper.OnSkinSwitchEvent += WindowHelper_OnSkinSwitchEvent;
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "OpcDa 客户端工具";
+            //配置文件名
+            FileName = typeof(OpcDaClientData).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 RelayCommand(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 RelayCommand(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("导出成功");
+            }
+        }
+
+        private string _info = string.Empty;
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => _info;
+            set => SetProperty(ref _info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new RelayCommand<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 Task Output(string Data, bool IsDate = true)
+        {
+            return Task.Run(() =>
+            {
+                System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                {
+                    if (Info?.Length > 10000)
+                    {
+                        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 RelayCommand(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>
+        private OpcDaClientOperate communication;
+
+        /// <summary>
+        /// 加载节点的生命周期
+        /// </summary>
+        private CancellationTokenSource tokenSource;
+
+        /// <summary>
+        /// 数据类型
+        /// </summary>
+        public int DataType
+        {
+            get => GetProperty(() => DataType);
+            set => SetProperty(() => DataType, value);
+        }
+        /// <summary>
+        /// 节点浏览是否点击
+        /// </summary>
+        public bool NodeBrowseIsChecked
+        {
+            get => GetProperty(() => NodeBrowseIsChecked);
+            set => SetProperty(() => NodeBrowseIsChecked, 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 Start { get => new RelayCommand(OnStart); }
+        private void OnStart()
+        {
+            communication = OpcDaClientOperate.Instance(BasicsData);
+            OperateResult operateResult = communication.On();
+            if (operateResult.State)
+            {
+                communication.OnEvent -= Communication_OnEvent;
+                communication.OnEvent += Communication_OnEvent;
+            }
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+
+        /// <summary>
+        /// 停止
+        /// </summary>
+        public ICommand Stop { get => new RelayCommand(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+
+        /// <summary>
+        /// 显示节点浏览命令
+        /// </summary>
+        public ICommand ToggleButton_Checked { get => new RelayCommand<RoutedEventArgs>(OnToggleButton_Checked); }
+        private void OnToggleButton_Checked(RoutedEventArgs e)
+        {
+            if (communication != null && communication.GetStatus().State)
+            {
+                NodeBrowseIsChecked = true;
+                BasicsData_ToggleButtonIsChecked = true;
+                if (tokenSource == null)
+                {
+                    tokenSource = new CancellationTokenSource();
+                }
+                //实例化对象
+                Node = new ObservableCollection<NodeStructuralBody>();
+                //获取所有节点
+                GetNodeInform(null, null, tokenSource);
+            }
+            else
+            {
+                Output("请先打开连接");
+                NodeBrowseIsChecked = false;
+            }
+        }
+
+        /// <summary>
+        /// 隐藏节点浏览命令
+        /// </summary>
+        public ICommand ToggleButton_Unchecked { get => new RelayCommand<RoutedEventArgs>(OnToggleButton_Unchecked); }
+        private void OnToggleButton_Unchecked(RoutedEventArgs e)
+        {
+            BasicsData_ToggleButtonIsChecked = false;
+            if (tokenSource != null)
+            {
+                tokenSource.Cancel();
+                tokenSource = null;
+            }
+            Node?.Clear();
+            NodeMessage?.Clear();
+        }
+
+        /// <summary>
+        /// 读取
+        /// </summary>
+        public ICommand Read { get => new RelayCommand(OnRead); }
+        public void OnRead()
+        {
+
+            Address? address = OrganizationAddress();
+            if (address == null) return;
+            OperateResult operateResult = communication.Read(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 订阅
+        /// </summary>
+        public ICommand Subscribe { get => new RelayCommand(OnSubscribe); }
+        public void OnSubscribe()
+        {
+            Address? address = OrganizationAddress();
+            if (address == null) return;
+            //订阅
+            OperateResult operateResult = communication.Subscribe(address);
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 写入
+        /// </summary>
+        public ICommand Write { get => new RelayCommand(OnWrite); }
+        public void OnWrite()
+        {
+            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 ICommand UnSubscribe { get => new RelayCommand(OnUnSubscribe); }
+        public void OnUnSubscribe()
+        {
+            Address? address = OrganizationAddress();
+            if (address == null) return;
+            //取消订阅
+            OperateResult operateResult = communication.UnSubscribe(address);
+            //信息输出
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 树控件被选中
+        /// </summary>
+        public ICommand TreeView_SelectedItemChanged { get => new RelayCommand<System.Windows.RoutedPropertyChangedEventArgs<object>>(OnTreeView_SelectedItemChanged); }
+        public void OnTreeView_SelectedItemChanged(System.Windows.RoutedPropertyChangedEventArgs<object> e)
+        {
+            NodeStructuralBody? nodeStructuralBody = e.NewValue as NodeStructuralBody;
+            ReferenceDescription? referenceDescription = nodeStructuralBody?.NodeID as ReferenceDescription;
+            NodeId? nodeId = (NodeId)referenceDescription?.NodeId;
+            if (nodeStructuralBody?.Children.Count == 1 && string.IsNullOrWhiteSpace(nodeStructuralBody?.Children[0].Name))
+            {
+                nodeStructuralBody?.Children.Clear();
+                GetNodeInform(nodeId, nodeStructuralBody, tokenSource);
+            }
+            if (nodeId != null)
+            {
+                //节点地址赋值
+                DotAddress = nodeId.ToString();
+
+                //实例化节点数据
+                List<NodeId> nodeIds = new List<NodeId>();
+
+                if (nodeStructuralBody?.Children.Count > 0)  //读取节点下的数据
+                {
+                    //汇总节点数据
+                    foreach (var item in nodeStructuralBody.Children)
+                    {
+                        nodeIds.Add((NodeId)(item?.NodeID as ReferenceDescription)?.NodeId);
+                    }
+                }
+                else   //读取当前节点数据
+                {
+                    nodeIds.Add(nodeId);
+                }
+
+                DataValue[] dataValues = communication.DetailedReadAllNodeData(nodeIds);
+
+                if (dataValues != null)
+                {
+                    ShowDetailedMessage(dataValues, nodeIds);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 表格列被选中
+        /// </summary>
+        public ICommand DataGrid_SelectedCellsChanged { get => new RelayCommand<object>(OnDataGrid_SelectedCellsChanged); }
+        public void OnDataGrid_SelectedCellsChanged(object e)
+        {
+            if (NodeMessageSelectedItem?.Name == null)
+            {
+                return;
+            }
+            DotAddress = NodeMessageSelectedItem?.Address;
+        }
+
+        /// <summary>
+        /// treeviewitem  被展开
+        /// </summary>
+        public ICommand TreeViewItem_Expanded { get => new RelayCommand<RoutedEventArgs>(OnTreeViewItem_Expanded); }
+        private void OnTreeViewItem_Expanded(RoutedEventArgs e)
+        {
+            TreeViewItem? treeViewItem = e.OriginalSource as TreeViewItem;
+            NodeStructuralBody? nodeStructuralBody = treeViewItem?.DataContext as NodeStructuralBody;
+            ReferenceDescription? referenceDescription = nodeStructuralBody?.NodeID as ReferenceDescription;
+            NodeId? nodeId = (NodeId)referenceDescription?.NodeId;
+            if (nodeStructuralBody?.Children.Count == 1 && string.IsNullOrWhiteSpace(nodeStructuralBody?.Children[0].Name))
+            {
+                nodeStructuralBody?.Children.Clear();
+                GetNodeInform(nodeId, nodeStructuralBody, tokenSource);
+            }
+        }
+
+        /// <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="nodeId">节点信息</param>
+        /// <param name="nodeStructuralBody">节点存储地方</param>
+        /// <param name="token">生命周期令牌</param>
+        /// <param name="depth">获取的深度</param>
+        /// <returns></returns>
+        private Task GetNodeInform(NodeId? nodeId, NodeStructuralBody? nodeStructuralBody, CancellationTokenSource token)
+        {
+            //异步
+            return Task.Run(() =>
+            {
+                //起一个新线程
+                return Task.Factory.StartNew(() =>
+                {
+                    try
+                    {
+                        //当前列下所有节点
+                        ReferenceDescriptionCollection references;
+
+                        //说明这是最开始的获取,没有nodeid
+                        if (nodeId == null)
+                        {
+                            //第一次获取
+                            references = communication.GetAllNode(communication.GetNodeID()).Result;
+                        }
+                        else
+                        {
+                            //这是获取下一层了
+                            references = communication.GetAllNode(nodeId).Result;
+                        }
+
+                        //获取成功
+                        if (references != null && references.Count > 0)
+                        {
+                            //遍历数据
+                            foreach (var item in references)
+                            {
+                                //当前节点信息
+                                ReferenceDescription target = item;
+                                //得到这个节点下有多少个节点
+                                ReferenceDescriptionCollection descriptions = communication.GetAllNode((NodeId)target.NodeId).Result;
+                                if (descriptions != null)
+                                {
+                                    System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                                    {
+                                        try
+                                        {
+                                            //当前节点下有多少节点数量
+                                            int count = descriptions.Count;
+                                            //获取展示图标
+                                            string imageName = communication.GetNodeIconType(target, communication.GetNodeID());
+                                            DrawingImage? drawingImage = (DrawingImage)System.Windows.Application.Current.FindResource(imageName);
+
+                                            //新建一个结构体
+                                            NodeStructuralBody structuralBody = new NodeStructuralBody() { Name = target.BrowseName.Name, Icon = drawingImage, NodeID = target, Count = count > 0 ? $"( {count} )" : string.Empty };
+
+                                            //看此节点下是否存在节点
+                                            if (count > 0)
+                                            {
+                                                //有数据的话,随便加一个,让其展示折叠图标
+                                                structuralBody.Children.Add(new NodeStructuralBody());
+                                            }
+                                            //当没传为空时,则使用集合添加
+                                            if (nodeStructuralBody == null)
+                                            {
+                                                Node.Add(structuralBody);
+                                            }
+                                            else
+                                            {
+                                                //添加新的节点
+                                                nodeStructuralBody.Children.Add(structuralBody);
+                                            }
+                                        }
+                                        catch { }
+                                    });
+                                }
+                            }
+                        }
+                    }
+                    catch { }
+                }, token.Token);
+            }, token.Token);
+        }
+
+        /// <summary>
+        /// 组织地址
+        /// </summary>
+        /// <returns></returns>
+        private Address? OrganizationAddress()
+        {
+            YSAI.Model.@enum.DataType dataType = Model.@enum.DataType.String;
+            try
+            {
+                switch (DataType)
+                {
+                    case 0:  //string
+                        dataType = Model.@enum.DataType.String;
+                        break;
+                    case 1:  //double
+                        dataType = Model.@enum.DataType.Double;
+                        break;
+                    case 2:  //float
+                        dataType = Model.@enum.DataType.Float;
+                        break;
+                    case 3:  //int
+                        dataType = Model.@enum.DataType.Int;
+                        break;
+                    case 4:  //bool
+                        dataType = Model.@enum.DataType.Bool;
+                        break;
+                }
+            }
+            catch (Exception ex)
+            {
+                Output($"数据格式不正确:{ex.Message}");
+                return null;
+            }
+
+            Address address = new Address();
+            address.AddressArray = new List<AddressDetails>()
+            {
+                new AddressDetails()
+                {
+                    AddressName = DotAddress,
+                    AddressDataType=dataType,
+                }
+            };
+            return address;
+        }
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            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}\r\n键:{itemc.Key}\r\n值:{itemc.Value.Value}\r\n", false);
+                    }
+                }
+            }
+        }
+
+        #region 右键菜单功能
+        /*
+        /// <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;
+        }
+
+        /// <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>
+        /// <returns></returns>
+        private DependencyObject VisualUpwardSearch<T>(DependencyObject source)
+        {
+            while (source != null && source.GetType() != typeof(T))
+                source = VisualTreeHelper.GetParent(source);
+            return source;
+        }
+
+        /// <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 ICommand TreeView_PreviewMouseRightButtonDown { get => new RelayCommand<MouseButtonEventArgs>(OnTreeView_PreviewMouseRightButtonDown); }
+
+        /// <summary>
+        /// 批量订阅
+        /// </summary>
+        public ICommand ContextMenu_Subscribe { get => new RelayCommand<object>(OnContextMenu_Subscribe); }
+
+        /// <summary>
+        /// 取消批量订阅
+        /// </summary>
+        public ICommand ContextMenu_UnSubscribe { get => new RelayCommand<Object>(OnContextMenu_UnSubscribe); }
+
+        /// <summary>
+        /// 导出节点
+        /// </summary>
+        public ICommand ContextMenu_ExpNode { get => new RelayCommand<object>(OnContextMenu_ExpNode); }
+
+
+        /// <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.UnSubscribe(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}");
+            }
+        }*/
+        #endregion
+    }
+}

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

@@ -34,7 +34,7 @@ namespace YSAI.Tool.Wpf.controllers
                         {
                             CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "UA"), SymbolRegular.DocumentTextToolbox24, typeof(UaClient)),
                             CreationControl(string.Format("{0,-8}{1}", "[ 服务端 ]", "UA"), SymbolRegular.DesktopToolbox24, typeof(UaService)),
-                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "DA ( x86 run )"), SymbolRegular.ClockToolbox24, typeof(AboutUs)),
+                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "DA ( x86 run )"), SymbolRegular.ClockToolbox24, typeof(DaClient)),
                             CreationControl(string.Format("{0,-8}{1}", "[ HTTP ]", "DA"), SymbolRegular.BookToolbox24, typeof(DaHttp))
                         }
                   },

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

@@ -0,0 +1,602 @@
+<UserControl x:Class="YSAI.Tool.Wpf.views.DaClient"
+             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: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:DaClientController />
+    </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" IsChecked="{Binding NodeBrowseIsChecked}">
+                    <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=2}" Style="{StaticResource RadioButtonStyle}" Content="Float" VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="3" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=3}"  Style="{StaticResource RadioButtonStyle}" Content="Int"  VerticalAlignment="Center" HorizontalAlignment="Center" />
+                                            <RadioButton Grid.Column="4" ToolTip="数据类型"  IsChecked="{Binding DataType,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=4}" 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 Read}" 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 Write}" 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 Subscribe}" 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 UnSubscribe}" 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>
+                                            <!--项被展开-->
+                                            <mvvm:RoutedEventTrigger RoutedEvent="TreeViewItem.Expanded">
+                                                <mvvm:EventCommand  Command="{Binding TreeViewItem_Expanded}" />
+                                            </mvvm:RoutedEventTrigger>
+                                        </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>
+
+

+ 28 - 0
src/YSAI.Tool.Wpf/views/DaClient.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.views
+{
+    /// <summary>
+    /// DaClient.xaml 的交互逻辑
+    /// </summary>
+    public partial class DaClient : UserControl
+    {
+        public DaClient()
+        {
+            InitializeComponent();
+        }
+    }
+}