Ver código fonte

1. 新增Ws客户端,服务端
2. 优化Ws Core
3. 串口、Tcp客户端改造完成

Shun 2 anos atrás
pai
commit
62f02e99fc

+ 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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.37706</Version>
+    <Version>23.353.7484</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>

+ 21 - 12
src/YSAI.Core/communication/net/ws/service/WsServiceOperate.cs

@@ -336,9 +336,9 @@ namespace YSAI.Core.communication.net.ws.service
         /// 数据发送
         /// </summary>
         /// <param name="Data">字节数据</param>
-        /// <param name="IpPort">地址</param>
+        /// <param name="Address">地址</param>
         /// <returns></returns>
-        public OperateResult Send(byte[] Data, string? IpPort = null)
+        public OperateResult Send(byte[] Data, string[]? Address = null)
         {
             string SN = Depart("Send");
             try
@@ -346,7 +346,7 @@ namespace YSAI.Core.communication.net.ws.service
                 if (Communication != null)
                 {
                     List<string> Message = new List<string>();
-                    if (string.IsNullOrEmpty(IpPort))
+                    if (Address == null)
                     {
                         //群发
                         foreach (var client in ClientIoc)
@@ -373,21 +373,30 @@ namespace YSAI.Core.communication.net.ws.service
                     }
                     else
                     {
-                        //指定发送
-                        if (ClientIoc.ContainsKey(IpPort))
+
+                        List<string> FailMessage = new List<string>();
+                        foreach (var IpPort in Address)
                         {
-                            try
+                            //指定发送
+                            if (ClientIoc.ContainsKey(IpPort))
                             {
-                                ClientIoc[IpPort].WebSocketObj.WebSocket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Text, true, CancellationToken.None);
+                                try
+                                {
+                                    ClientIoc[IpPort].WebSocketObj.WebSocket.SendAsync(new ArraySegment<byte>(Data), WebSocketMessageType.Text, true, CancellationToken.None);
+                                }
+                                catch (Exception ex)
+                                {
+                                    FailMessage.Add($"数据发送[{IpPort}]异常:{ex.Message}");
+                                }
                             }
-                            catch (Exception ex)
+                            else
                             {
-                                return Break(SN, false, $"数据发送[{IpPort}]异常:{ex.Message}", Message, ResultType.Object);
+                                FailMessage.Add($"数据发送失败,[{IpPort}]不存在");
                             }
                         }
-                        else
+                        if (FailMessage.Count > 0)
                         {
-                            return Break(SN, false, $"数据发送失败,[{IpPort}]不存在", Message, ResultType.Object);
+                            return Break(SN, false, FailMessage.ToJson(), FailMessage, ResultType.Object);
                         }
                     }
                     return Break(SN, true);
@@ -403,7 +412,7 @@ namespace YSAI.Core.communication.net.ws.service
             }
         }
 
-        public Task<OperateResult> SendAsync(byte[] Data, string? Address = null)
+        public Task<OperateResult> SendAsync(byte[] Data, string[]? Address = null)
         {
             return Task.Run(() => Send(Data, Address));
         }

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

@@ -99,7 +99,7 @@
 
   <ItemGroup>
     <PackageReference Include="YSAI.Mqtt" Version="23.352.38022" />
-    <PackageReference Include="YSAI.Opc" Version="23.352.38022" />
+    <PackageReference Include="YSAI.Opc" Version="23.353.7802" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </ItemGroup>
 </Project>

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

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.352.38022</Version>
+    <Version>23.353.7802</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="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.76" />
-    <PackageReference Include="YSAI.Core" Version="23.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </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.352.38022</Version>
+    <Version>23.353.7802</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.352.37706" />
+    <PackageReference Include="YSAI.Core" Version="23.353.7484" />
   </ItemGroup>
 </Project>

+ 241 - 241
src/YSAI.Tests/Program.cs

@@ -1,16 +1,16 @@
 
 
-using YSAI.Core.communication.net.tcp.service;
-using YSAI.Unility;
+//using YSAI.Core.communication.net.tcp.service;
+//using YSAI.Unility;
 
-TcpServiceOperate tcpServiceOperate = TcpServiceOperate.Instance(new TcpServiceData.Basics());
-Console.WriteLine(tcpServiceOperate.On().ToJson().JsonFormatting());
+//TcpServiceOperate tcpServiceOperate = TcpServiceOperate.Instance(new TcpServiceData.Basics());
+//Console.WriteLine(tcpServiceOperate.On().ToJson().JsonFormatting());
 
 
 
-Thread.Sleep(3000);
+//Thread.Sleep(3000);
 
-Console.WriteLine(tcpServiceOperate.Off().ToJson().JsonFormatting());
+//Console.WriteLine(tcpServiceOperate.Off().ToJson().JsonFormatting());
 
 
 
@@ -190,241 +190,241 @@ Console.WriteLine(tcpServiceOperate.Off().ToJson().JsonFormatting());
 
 
 
-//using System.Collections.Concurrent;
-//using YSAI.Core.reflection;
-//using YSAI.Core.script;
-//using YSAI.Log;
-//using YSAI.Model.data;
-//using YSAI.Model.@enum;
-//using YSAI.Mqtt.service;
-//using YSAI.Opc.ua.client;
-//using YSAI.Unility;
-///// <summary>
-///// 读取Csv,返回行集合
-///// </summary>
-///// <param name="path"></param>
-///// <param name="hasTitle"></param>
-///// <returns></returns>
-//List<string> ReadCsv(string path, bool hasTitle)
-//{
-//    if (!File.Exists(path))
-//        return new List<string>();
-
-//    var lines = File.ReadAllLines(path).ToList();
-//    if (hasTitle)
-//    {
-//        lines.RemoveAt(0);
-//    }
-//    return lines;
-//}
-
-////启动MQTT服务端 1
-//MqttServiceOperate mqttServiceOperate1 = MqttServiceOperate.Instance(new MqttServiceData.Basics
-//{
-//    MaxNumber = 1000,
-//    Password = "samples",
-//    UserName = "samples",
-//    Port = 8111
-//});
-////输出日志
-//LogHelper.Info(mqttServiceOperate1.On().ToJson().JsonFormatting());
-////启动MQTT服务端 2
-//MqttServiceOperate mqttServiceOperate2 = MqttServiceOperate.Instance(new MqttServiceData.Basics
-//{
-//    MaxNumber = 1000,
-//    Password = "samples",
-//    UserName = "samples",
-//    Port = 8222
-//});
-////输出日志
-//LogHelper.Info(mqttServiceOperate2.On().ToJson().JsonFormatting());
-
-
-
-
-//Address address = new Address();
-//address.SN = Guid.NewGuid().ToString();
-//address.CreationTime = DateTime.Now;
-//address.AddressArray = new List<AddressDetails>();
-//List<string> strings = ReadCsv("files\\6022.csv", true);
-//for (int i = 0; i < strings.Count; i++)
-//{
-//    string[] str = strings[i].Split(",");
-//    string addressD = str[0].Replace("\"", "");
-//    DataType dataType = DataType.String;
-//    if (str.Contains("Float"))
-//    {
-//        dataType = DataType.Float;
-//    }
-//    else if (str.Contains("Boolean"))
-//    {
-//        dataType = DataType.Bool;
-//    }
-//    else if (str.Contains("Short"))
-//    {
-//        dataType = DataType.Short;
-//    }
-
-//    if (i % 2 == 0)
-//    {
-//        //走脚本解析
-//        address.AddressArray.Add(new AddressDetails()
-//        {
-//            AddressName = $"ns=2;s=6022.6022.{addressD}",
-//            SN = Guid.NewGuid().ToString(),
-//            AddressDataType = dataType,
-//            AddressRelayParam = new AddressRelay
-//            {
-//                ISns = new List<string> { "YSAI.Mqtt.client.MqttClientOperate.mqtt1", "YSAI.Mqtt.client.MqttClientOperate.mqtt2" },
-//                Topic = $"TEST/{addressD}"
-//            },
-//            AddressParseParam = new AddressParse
-//            {
-//                ScriptParam = new ScriptData.Basics()
-//                {
-//                    ScriptCode = @"function Convert(addressname,value) { return '【这是调用脚本解析】传入的地址是:'+ addressname + '----传入的参数是:' + value; }",
-//                    ScriptFunction = "Convert",
-//                    ScriptType = ScriptData.ScriptType.JavaScript
-//                }
-//            }
-//        });
-//    }
-//    else
-//    {
-//        //走反射解析流程
-//        address.AddressArray.Add(new AddressDetails()
-//        {
-//            AddressName = $"ns=2;s=6022.6022.{addressD}",
-//            SN = Guid.NewGuid().ToString(),
-//            AddressDataType = dataType,
-//            AddressRelayParam = new AddressRelay
-//            {
-//                ISns = new List<string> { "YSAI.Mqtt.client.MqttClientOperate.mqtt1", "YSAI.Mqtt.client.MqttClientOperate.mqtt2" },
-//                Topic = $"TEST/{addressD}"
-//            },
-//            AddressParseParam = new AddressParse
-//            {
-//                ReflectionParam = new object[]
-//                {
-//                    new ReflectionData.Basics
-//                    {
-//                        DllDatas = new List<ReflectionData.DllData>
-//                        {
-//                            new ReflectionData.DllData
-//                            {
-//                                DllPath="YSAI.DAQ.Samples.Reflection.dll",
-//                                IsAbsolutePath=false,
-//                                NamespaceDatas=new List<ReflectionData.NamespaceData>
-//                                {
-//                                    new ReflectionData.NamespaceData
-//                                    {
-//                                        Namespace="YSAI.DAQ.Samples.Reflection",
-//                                        ClassDatas=new List<ReflectionData.ClassData>
-//                                        {
-//                                            new ReflectionData.ClassData
-//                                            {
-//                                                ClassName="Class1",
-//                                                SN="YSAI.DAQ.Samples.Reflection.Class1[Instance]",
-//                                                MethodDatas=new List<ReflectionData.MethodData>
-//                                                {
-//                                                    new ReflectionData.MethodData
-//                                                    {
-//                                                        MethodName="R1",
-//                                                        SN="[R1]"
-//                                                    },
-//                                                     new ReflectionData.MethodData
-//                                                    {
-//                                                        MethodName="R2",
-//                                                        SN="[R2]"
-//                                                    },
-//                                                      new ReflectionData.MethodData
-//                                                    {
-//                                                        MethodName="R3",
-//                                                        SN="[R3]"
-//                                                    }
-//                                                }
-//                                            }
-//                                        }
-//                                    }
-//                                }
-
-//                            }
-//                        }
-//                    },
-//                    "YSAI.DAQ.Samples.Reflection.Class1[Instance][R2]"
-//                }
-//            }
-//        });
-//    }
-//}
-
-//File.WriteAllText("config\\config.json", address.ToJson().JsonFormatting());
-
-//OpcUaClientOperate opcUaClientOperate = OpcUaClientOperate.Instance(new OpcUaClientData.Basics
-//{
-//    ServerUrl = "opc.tcp://192.168.2.220:49320",
-//    CustomName = "YSAI 性能测试",
-//    SubscribeSingleGroupMaxCount = 1000,
-//});
-//Console.WriteLine(opcUaClientOperate.On().ToJson().JsonFormatting());
-//opcUaClientOperate.OnEvent += OpcUaClientOperate_OnEvent;
-
-//while (true)
-//{
-//    Console.ReadLine();
-
-//    OperateResult operateResult = opcUaClientOperate.Subscribe(address);
-//    Console.WriteLine(operateResult.ToJson().JsonFormatting());
-//    Console.ReadLine();
-
-//    //OperateResult operateResult = opcUaClientOperate.Subscribe(address);
-//    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
-//    //Console.ReadLine();
-
-//    //operateResult = opcUaClientOperate.UnSubscribe(address);
-//    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
-//    //Console.ReadLine();
-//    //address = new Address();
-//    //address.SN = Guid.NewGuid().ToString();
-//    //address.CreationTime = DateTime.Now;
-//    //address.AddressArray = new List<AddressDetails>();
-//    //address.AddressArray.Add(new AddressDetails()
-//    //{
-//    //    AddressName = $"6666",
-//    //    SN = Guid.NewGuid().ToString()
-//    //});
-//    //operateResult = opcUaClientOperate.Subscribe(address);
-//    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
-
-//}
-
-//void OpcUaClientOperate_OnEvent(object? sender, EventResult e)
-//{
-//    switch (e.RType)
-//    {
-//        case ResultType.KeyValue:
-
-//            ConcurrentDictionary<string, AddressValue> pairs = e.GetRData<ConcurrentDictionary<string, AddressValue>>();
-//            foreach (var item in pairs)
-//            {
-//                if (item.Value.AddressName.Equals("ns=2;s=6022.6022.LAP5_DP2112_STATE_RUN") || item.Value.AddressName.Equals("ns=2;s=6022.6022.LAP5_DP2113_AUTO"))
-//                {
-//                    String str = string.Format("{0,-100}{1,-100}", item.Key, item.Value.Value);
-//                    LogHelper.Warning(item.Value.Quality.ToString());
-//                    LogHelper.Warning(item.Value.OriginalValue.GetType().Name);
-//                    LogHelper.Verbose(str);
-//                }
-
-//                //String str = String.Format("{0,-100}{1,-100}", item.Key, item.Value.Value);
-//                //LogHelper.Verbose(str);
-//            }
-//            break;
-
-//        default:
-//            //Console.WriteLine(e.Message);
-//            break;
-//    }
-//}
+using System.Collections.Concurrent;
+using YSAI.Core.reflection;
+using YSAI.Core.script;
+using YSAI.Log;
+using YSAI.Model.data;
+using YSAI.Model.@enum;
+using YSAI.Mqtt.service;
+using YSAI.Opc.ua.client;
+using YSAI.Unility;
+/// <summary>
+/// 读取Csv,返回行集合
+/// </summary>
+/// <param name="path"></param>
+/// <param name="hasTitle"></param>
+/// <returns></returns>
+List<string> ReadCsv(string path, bool hasTitle)
+{
+    if (!File.Exists(path))
+        return new List<string>();
+
+    var lines = File.ReadAllLines(path).ToList();
+    if (hasTitle)
+    {
+        lines.RemoveAt(0);
+    }
+    return lines;
+}
+
+//启动MQTT服务端 1
+MqttServiceOperate mqttServiceOperate1 = MqttServiceOperate.Instance(new MqttServiceData.Basics
+{
+    MaxNumber = 1000,
+    Password = "samples",
+    UserName = "samples",
+    Port = 8111
+});
+//输出日志
+LogHelper.Info(mqttServiceOperate1.On().ToJson().JsonFormatting());
+//启动MQTT服务端 2
+MqttServiceOperate mqttServiceOperate2 = MqttServiceOperate.Instance(new MqttServiceData.Basics
+{
+    MaxNumber = 1000,
+    Password = "samples",
+    UserName = "samples",
+    Port = 8222
+});
+//输出日志
+LogHelper.Info(mqttServiceOperate2.On().ToJson().JsonFormatting());
+
+
+
+
+Address address = new Address();
+address.SN = Guid.NewGuid().ToString();
+address.CreationTime = DateTime.Now;
+address.AddressArray = new List<AddressDetails>();
+List<string> strings = ReadCsv("files\\6022.csv", true);
+for (int i = 0; i < strings.Count; i++)
+{
+    string[] str = strings[i].Split(",");
+    string addressD = str[0].Replace("\"", "");
+    DataType dataType = DataType.String;
+    if (str.Contains("Float"))
+    {
+        dataType = DataType.Float;
+    }
+    else if (str.Contains("Boolean"))
+    {
+        dataType = DataType.Bool;
+    }
+    else if (str.Contains("Short"))
+    {
+        dataType = DataType.Short;
+    }
+
+    if (i % 2 == 0)
+    {
+        //走脚本解析
+        address.AddressArray.Add(new AddressDetails()
+        {
+            AddressName = $"ns=2;s=6022.6022.{addressD}",
+            SN = Guid.NewGuid().ToString(),
+            AddressDataType = dataType,
+            AddressRelayParam = new AddressRelay
+            {
+                ISns = new List<string> { "YSAI.Mqtt.client.MqttClientOperate.mqtt1", "YSAI.Mqtt.client.MqttClientOperate.mqtt2" },
+                Topic = $"TEST/{addressD}"
+            },
+            AddressParseParam = new AddressParse
+            {
+                ScriptParam = new ScriptData.Basics()
+                {
+                    ScriptCode = @"function Convert(addressname,value) { return '【这是调用脚本解析】传入的地址是:'+ addressname + '----传入的参数是:' + value; }",
+                    ScriptFunction = "Convert",
+                    ScriptType = ScriptData.ScriptType.JavaScript
+                }
+            }
+        });
+    }
+    else
+    {
+        //走反射解析流程
+        address.AddressArray.Add(new AddressDetails()
+        {
+            AddressName = $"ns=2;s=6022.6022.{addressD}",
+            SN = Guid.NewGuid().ToString(),
+            AddressDataType = dataType,
+            AddressRelayParam = new AddressRelay
+            {
+                ISns = new List<string> { "YSAI.Mqtt.client.MqttClientOperate.mqtt1", "YSAI.Mqtt.client.MqttClientOperate.mqtt2" },
+                Topic = $"TEST/{addressD}"
+            },
+            AddressParseParam = new AddressParse
+            {
+                ReflectionParam = new object[]
+                {
+                    new ReflectionData.Basics
+                    {
+                        DllDatas = new List<ReflectionData.DllData>
+                        {
+                            new ReflectionData.DllData
+                            {
+                                DllPath="YSAI.DAQ.Samples.Reflection.dll",
+                                IsAbsolutePath=false,
+                                NamespaceDatas=new List<ReflectionData.NamespaceData>
+                                {
+                                    new ReflectionData.NamespaceData
+                                    {
+                                        Namespace="YSAI.DAQ.Samples.Reflection",
+                                        ClassDatas=new List<ReflectionData.ClassData>
+                                        {
+                                            new ReflectionData.ClassData
+                                            {
+                                                ClassName="Class1",
+                                                SN="YSAI.DAQ.Samples.Reflection.Class1[Instance]",
+                                                MethodDatas=new List<ReflectionData.MethodData>
+                                                {
+                                                    new ReflectionData.MethodData
+                                                    {
+                                                        MethodName="R1",
+                                                        SN="[R1]"
+                                                    },
+                                                     new ReflectionData.MethodData
+                                                    {
+                                                        MethodName="R2",
+                                                        SN="[R2]"
+                                                    },
+                                                      new ReflectionData.MethodData
+                                                    {
+                                                        MethodName="R3",
+                                                        SN="[R3]"
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+
+                            }
+                        }
+                    },
+                    "YSAI.DAQ.Samples.Reflection.Class1[Instance][R2]"
+                }
+            }
+        });
+    }
+}
+
+File.WriteAllText("config\\config.json", address.ToJson().JsonFormatting());
+
+OpcUaClientOperate opcUaClientOperate = OpcUaClientOperate.Instance(new OpcUaClientData.Basics
+{
+    ServerUrl = "opc.tcp://192.168.2.220:49320",
+    CustomName = "YSAI 性能测试",
+    SubscribeSingleGroupMaxCount = 1000,
+});
+Console.WriteLine(opcUaClientOperate.On().ToJson().JsonFormatting());
+opcUaClientOperate.OnEvent += OpcUaClientOperate_OnEvent;
+
+while (true)
+{
+    Console.ReadLine();
+
+    OperateResult operateResult = opcUaClientOperate.Subscribe(address);
+    Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    Console.ReadLine();
+
+    //OperateResult operateResult = opcUaClientOperate.Subscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    //Console.ReadLine();
+
+    //operateResult = opcUaClientOperate.UnSubscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    //Console.ReadLine();
+    //address = new Address();
+    //address.SN = Guid.NewGuid().ToString();
+    //address.CreationTime = DateTime.Now;
+    //address.AddressArray = new List<AddressDetails>();
+    //address.AddressArray.Add(new AddressDetails()
+    //{
+    //    AddressName = $"6666",
+    //    SN = Guid.NewGuid().ToString()
+    //});
+    //operateResult = opcUaClientOperate.Subscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+}
+
+void OpcUaClientOperate_OnEvent(object? sender, EventResult e)
+{
+    switch (e.RType)
+    {
+        case ResultType.KeyValue:
+
+            ConcurrentDictionary<string, AddressValue> pairs = e.GetRData<ConcurrentDictionary<string, AddressValue>>();
+            foreach (var item in pairs)
+            {
+                if (item.Value.AddressName.Equals("ns=2;s=6022.6022.LAP5_DP2112_STATE_RUN") || item.Value.AddressName.Equals("ns=2;s=6022.6022.LAP5_DP2113_AUTO"))
+                {
+                    String str = string.Format("{0,-100}{1,-100}", item.Key, item.Value.Value);
+                    LogHelper.Warning(item.Value.Quality.ToString());
+                    LogHelper.Warning(item.Value.OriginalValue.GetType().Name);
+                    LogHelper.Verbose(str);
+                }
+
+                //String str = String.Format("{0,-100}{1,-100}", item.Key, item.Value.Value);
+                //LogHelper.Verbose(str);
+            }
+            break;
+
+        default:
+            //Console.WriteLine(e.Message);
+            break;
+    }
+}
 
 
 

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

@@ -17,21 +17,21 @@
 		<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.352.38022" />
-		<PackageReference Include="YSAI.Beckhoff" Version="23.352.38022" />
-		<PackageReference Include="YSAI.DB" Version="23.352.38022" />
+		<PackageReference Include="YSAI.AllenBradley" Version="23.353.7802" />
+		<PackageReference Include="YSAI.Beckhoff" Version="23.353.7802" />
+		<PackageReference Include="YSAI.DB" Version="23.353.7802" />
 		<PackageReference Include="YSAI.Kafka" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Mewtocol" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Mitsubishi" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Modbus" 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.Mqtt" Version="23.352.38022" />
 		<PackageReference Include="YSAI.NetMQ" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Netty" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Omron" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Opc" Version="23.352.38022" />
+		<PackageReference Include="YSAI.Omron" Version="23.353.7802" />
+		<PackageReference Include="YSAI.Opc" Version="23.353.7802" />
 		<PackageReference Include="YSAI.RabbitMQ" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Redis" Version="23.352.38022" />
-		<PackageReference Include="YSAI.Siemens" Version="23.352.38022" />
+		<PackageReference Include="YSAI.Siemens" Version="23.353.7802" />
 	</ItemGroup>
 	<ItemGroup>
 		<ProjectReference Include="..\YSAI.Core.Wpf\YSAI.Core.Wpf.csproj" />

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

@@ -33,7 +33,7 @@ namespace YSAI.Tool.Wpf.controllers
                         {
                             CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "UA"), SymbolRegular.DocumentTextToolbox24, typeof(AboutUs)),
                             CreationControl(string.Format("{0,-8}{1}", "[ 服务端 ]", "UA"), SymbolRegular.DesktopToolbox24, typeof(AboutUs)),
-                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "DA"), SymbolRegular.ClockToolbox24, null),
+                            CreationControl(string.Format("{0,-8}{1}", "[ 客户端 ]", "DA ( x86 run )"), SymbolRegular.ClockToolbox24, null),
                             CreationControl(string.Format("{0,-8}{1}", "[ HTTP ]", "DA"), SymbolRegular.BookToolbox24, typeof(AboutUs))
                         }
                   },
@@ -60,9 +60,19 @@ namespace YSAI.Tool.Wpf.controllers
                             CreationControl(string.Format("{0,-8}{1}", "[ 服务端 ]", "Tcp"), SymbolRegular.DesktopToolbox24, typeof(TcpService)),
                             CreationControl("Udp", SymbolRegular.ClockToolbox24, typeof(Udp))
                         }
+                  },
+                   new NavigationViewItem()
+                  {
+                        NavigationCacheMode=NavigationCacheMode.Required,
+                        Content = "WebScoket",
+                        Icon = new SymbolIcon { Symbol = SymbolRegular.Toolbox12 , Filled = true },
+                        MenuItems = new object[]
+                        {
+                            CreationControl("[ 客户端 ]", SymbolRegular.DocumentTextToolbox24, typeof(WsClient)),
+                            CreationControl("[ 服务端 ]", SymbolRegular.DesktopToolbox24, typeof(WsService)),
+                        }
                   },
                   CreationControl("Serial",SymbolRegular.Toolbox12,typeof(Serial)),
-                  CreationControl("CAN",SymbolRegular.Toolbox12,null),
                   CreationControl("Svg",SymbolRegular.Toolbox12,typeof(Svg)),
                    CreationControl("Test",SymbolRegular.Toolbox12,typeof(test)),
             };

+ 170 - 270
src/YSAI.Tool.Wpf/controllers/SerialController.cs

@@ -1,409 +1,309 @@
-using System.Collections.ObjectModel;
-using System.IO.Ports;
+using System.IO;
 using System.Text;
+using System.Windows;
 using System.Windows.Input;
 using YSAI.Core.communication.serial;
-using YSAI.Core.Wpf;
 using YSAI.Core.Wpf.mvvm;
 using YSAI.Langs;
 using YSAI.Model.data;
 using YSAI.Unility;
+using static YSAI.Core.communication.serial.SerialData;
 using SerialData = YSAI.Core.communication.serial.SerialData;
 
 namespace YSAI.Tool.Wpf.controllers
 {
     public class SerialController : NotifyObject
     {
-        /// <summary>
-        /// 波特率
-        /// </summary>
-        public int[] BaudRateList = new int[] { 1200, 2400, 4800, 7200, 9600, 14400, 19200, 28800, 38400, 57600, 115200, 128000, 153600, 230400, 256000 };
-        /// <summary>
-        /// 校验位
-        /// </summary>
-        public string[] ParityBitList = new string[] { Parity.None.ToString(), Parity.Odd.ToString(), Parity.Even.ToString(), Parity.Mark.ToString(), Parity.Space.ToString() };
-        /// <summary>
-        /// 数据位
-        /// </summary>
-        public int[] DataBitList = new int[] { 5, 6, 7, 8 };
-        /// <summary>
-        /// 停止位
-        /// </summary>
-        public string[] StopBitList = new string[] { StopBits.One.ToString(), StopBits.Two.ToString(), StopBits.OnePointFive.ToString() };
-        /// <summary>
-        /// 串口通信操作
-        /// </summary>
-        public SerialOperate serialPortOperator;
         public SerialController()
         {
             //设置初始语言
             LangsHelper.SetLangs(LangsHelper.GetLangs());
-            //初始化值
-            InitValue();
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Tcp 客户端工具";
+            //配置文件名
+            FileName = typeof(SerialData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Visible;
+            //Hex是否显示
+            HexVisibility = Visibility.Visible;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
         }
 
+        #region 统一需要的数据
         /// <summary>
-        /// 初始化值
+        /// 导出的文件名
         /// </summary>
-        void InitValue()
-        {
-            LedIsOn = false;
-            Channel_ComboBoxDataList = new ObservableCollection<ComboBoxData>();
-            foreach (string SerialPortList in SerialPort.GetPortNames())
-            {
-                Channel_ComboBoxDataList.Add(new ComboBoxData() { Key = SerialPortList, Value = SerialPortList });
-            }
-            if (Channel_ComboBoxDataList.Count > 0)
-            {
-                Channel_SelectedComboBoxData = Channel_ComboBoxDataList[0];
-            }
-            BaudRate_ComboBoxDataList = new ObservableCollection<ComboBoxData>();
-            foreach (var item in BaudRateList)
-            {
-                BaudRate_ComboBoxDataList.Add(new ComboBoxData() { Key = item.ToString(), Value = item.ToString() });
-            }
-            BaudRate_SelectedComboBoxData = BaudRate_ComboBoxDataList[4];
-            ParityBit_ComboBoxDataList = new ObservableCollection<ComboBoxData>();
-            foreach (var item in ParityBitList)
-            {
-                ParityBit_ComboBoxDataList.Add(new ComboBoxData() { Key = item.ToString(), Value = item.ToString() });
-            }
-            ParityBit_SelectedComboBoxData = ParityBit_ComboBoxDataList[0];
-            StopBit_ComboBoxDataList = new ObservableCollection<ComboBoxData>();
-            foreach (var item in StopBitList)
-            {
-                StopBit_ComboBoxDataList.Add(new ComboBoxData() { Key = item.ToString(), Value = item.ToString() });
-            }
-            StopBit_SelectedComboBoxData = StopBit_ComboBoxDataList[0];
-            DataBit_ComboBoxDataList = new ObservableCollection<ComboBoxData>();
-            foreach (var item in DataBitList)
-            {
-                DataBit_ComboBoxDataList.Add(new ComboBoxData() { Key = item.ToString(), Value = item.ToString() });
-            }
-            DataBit_SelectedComboBoxData = DataBit_ComboBoxDataList[3];
-        }
-
+        private string FileName { get; set; }
         /// <summary>
-        /// 下拉框设备数据
+        /// 工具标题
         /// </summary>
-        public class ComboBoxData
+        public string ToolTitle
         {
-            /// <summary>
-            /// 键
-            /// </summary>
-            public string? Key { set; get; }
-            /// <summary>
-            /// 值
-            /// </summary>
-            public string? Value { set; get; }
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
         }
         /// <summary>
-        /// 串口号  下拉框数据集合
+        /// 数据源
         /// </summary>
-        public ObservableCollection<ComboBoxData> Channel_ComboBoxDataList
+        public Basics BasicsData
         {
-            get => GetProperty(() => Channel_ComboBoxDataList);
-            set => SetProperty(() => Channel_ComboBoxDataList, value);
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
         }
 
         /// <summary>
-        /// 串口号  下拉框已选中的数据
+        /// 导入基础数据命令
         /// </summary>
-        public ComboBoxData Channel_SelectedComboBoxData
-        {
-            get => GetProperty(() => Channel_SelectedComboBoxData);
-            set => SetProperty(() => Channel_SelectedComboBoxData, value);
-        }
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
 
         /// <summary>
-        /// 波特率  下拉框数据集合
+        /// 导入基础数据
         /// </summary>
-        public ObservableCollection<ComboBoxData> BaudRate_ComboBoxDataList
+        public void OnIncBasics()
         {
-            get => GetProperty(() => BaudRate_ComboBoxDataList);
-            set => SetProperty(() => BaudRate_ComboBoxDataList, value);
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (BasicsData == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
         }
 
         /// <summary>
-        /// 波特率  下拉框已选中的数据
+        /// 导出基础数据命令
         /// </summary>
-        public ComboBoxData BaudRate_SelectedComboBoxData
-        {
-            get => GetProperty(() => BaudRate_SelectedComboBoxData);
-            set => SetProperty(() => BaudRate_SelectedComboBoxData, value);
-        }
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
 
         /// <summary>
-        /// 校验位  下拉框数据集合
+        /// 导出基础数据
         /// </summary>
-        public ObservableCollection<ComboBoxData> ParityBit_ComboBoxDataList
+        public void OnExpBasics()
         {
-            get => GetProperty(() => ParityBit_ComboBoxDataList);
-            set => SetProperty(() => ParityBit_ComboBoxDataList, value);
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
         }
 
         /// <summary>
-        /// 校验位  下拉框已选中的数据
+        /// 信息
         /// </summary>
-        public ComboBoxData ParityBit_SelectedComboBoxData
+        public string Info
         {
-            get => GetProperty(() => ParityBit_SelectedComboBoxData);
-            set => SetProperty(() => ParityBit_SelectedComboBoxData, value);
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
         }
 
         /// <summary>
-        /// 停止位  下拉框数据集合
+        /// 信息框事件
         /// </summary>
-        public ObservableCollection<ComboBoxData> StopBit_ComboBoxDataList
-        {
-            get => GetProperty(() => StopBit_ComboBoxDataList);
-            set => SetProperty(() => StopBit_ComboBoxDataList, value);
-        }
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
-        /// 停止位  下拉框已选中的数据
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
         /// </summary>
-        public ComboBoxData StopBit_SelectedComboBoxData
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
         {
-            get => GetProperty(() => StopBit_SelectedComboBoxData);
-            set => SetProperty(() => StopBit_SelectedComboBoxData, value);
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
         }
+
         /// <summary>
-        /// 数据位  下拉框数据集合
+        /// 输出标准消息
         /// </summary>
-        public ObservableCollection<ComboBoxData> DataBit_ComboBoxDataList
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
         {
-            get => GetProperty(() => DataBit_ComboBoxDataList);
-            set => SetProperty(() => DataBit_ComboBoxDataList, value);
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
         }
-
         /// <summary>
-        /// 数据位  下拉框已选中的数据
+        /// ascii
         /// </summary>
-        public ComboBoxData DataBit_SelectedComboBoxData
+        public Visibility AsciiVisibility
         {
-            get => GetProperty(() => DataBit_SelectedComboBoxData);
-            set => SetProperty(() => DataBit_SelectedComboBoxData, value);
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
         }
-
-
         /// <summary>
-        /// 让LED灯闪烁
+        /// hex
         /// </summary>
-        public bool LedIsFlashing
+        public Visibility HexVisibility
         {
-            get => GetProperty(() => LedIsFlashing);
-            set => SetProperty(() => LedIsFlashing, value);
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
         }
 
         /// <summary>
-        /// 是否使用LED
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
         /// </summary>
-        public bool LedIsOn
+        public int InfoFormat
         {
-            get => GetProperty(() => LedIsOn);
-            set
-            {
-                SetProperty(() => LedIsOn, value);
-                if (value)//如果开始使用LED 则触发
-                {
-                    LedColor = System.Windows.Media.Colors.Green;
-                    LedIsFlashing = true;
-                }
-                else
-                {
-                    LedColor = System.Windows.Media.Colors.Gray;
-                    LedIsFlashing = false;
-                }
-            }
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
         }
+
         /// <summary>
-        /// Led颜色
+        /// 清空信息命令
         /// </summary>
-        public System.Windows.Media.Color LedColor
-        {
-            get => GetProperty(() => LedColor);
-            set => SetProperty(() => LedColor, value);
-        }
+        public ICommand Clear { get => new CommandX(OnClear); }
 
         /// <summary>
-        /// 数据发送文本
+        /// 清空信息
         /// </summary>
-        public string SendData
+        public void OnClear()
         {
-            get => GetProperty(() => SendData);
-            set => SetProperty(() => SendData, value);
+            Info = string.Empty;
         }
+
+        #endregion 统一需要的数据
+
+
         /// <summary>
-        /// 发送的数据类型
+        /// 通信
         /// </summary>
-        public int SendDataFormat
-        {
-            get => GetProperty(() => SendDataFormat);
-            set => SetProperty(() => SendDataFormat, value);
-        }
+        private SerialOperate communication;
 
         /// <summary>
-        /// 数据接收文本
+        /// 启动
         /// </summary>
-        public string ReceiveData
+        public ICommand Start { get => new CommandX(OnStart); }
+        private void OnStart()
         {
-            get => GetProperty(() => ReceiveData);
-            set => SetProperty(() => ReceiveData, value);
+            communication = SerialOperate.Instance(BasicsData);
+            OperateResult operateResult = communication.On();
+            if (operateResult.State)
+            {
+                communication.OnEvent -= Communication_OnEvent; ;
+                communication.OnEvent += Communication_OnEvent;
+            }
+            Output(operateResult.ToJson().JsonFormatting());
         }
         /// <summary>
-        /// 接收的数据类型
+        /// 停止
         /// </summary>
-        public int ReceiveDataFormat
+        public ICommand Stop { get => new CommandX(OnStop); }
+        private void OnStop()
         {
-            get => GetProperty(() => ReceiveDataFormat);
-            set => SetProperty(() => ReceiveDataFormat, value);
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
         }
 
         /// <summary>
-        /// 发送数据
+        /// 发送
         /// </summary>
-        public void OnSend()
+        public ICommand Send { get => new CommandX(OnSend); }
+        private void OnSend()
         {
-            if (!serialPortOperator.GetStatus().State)
-            {
-                MessageBox.Show(LangsHelper.GetValue("msg1"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                return;
-            }
-
-            if (string.IsNullOrEmpty(SendData))
-            {
-                MessageBox.Show(LangsHelper.GetValue("msg3"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                return;
-            }
-            if (SendDataFormat.Equals(0))
+            if (communication == null) return;
+            //发送的数据
+            byte[] sendData = null;
+            if (DataFormat.Equals(0))
             {
-                if (!serialPortOperator.Send(Encoding.ASCII.GetBytes(SendData)).State)
-                {
-                    MessageBox.Show(LangsHelper.GetValue("msg4"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                }
+                sendData = Encoding.ASCII.GetBytes(SendData);
             }
             else
             {
                 if (ValidatorTool.IsHexadecimal(SendData))
                 {
-                    if (!serialPortOperator.Send(SendData.ToHex()).State)
-                    {
-                        MessageBox.Show(LangsHelper.GetValue("msg4"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                    }
+                    sendData = ByteTool.HexStringToByteArray(SendData);
                 }
                 else
                 {
-                    MessageBox.Show(LangsHelper.GetValue("msg5"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
+                    Output($"“{SendData}”不是有效的 Hex 数据");
                 }
             }
-        }
-        public ICommand Send { get => new CommandX(OnSend); }
-
-        /// <summary>
-        /// 清空数据
-        /// </summary>
-        public void OnEmpty()
-        {
-            ReceiveData = string.Empty;
-        }
-        public ICommand Empty { get => new CommandX(OnEmpty); }
-
-        /// <summary>
-        /// 打开串口
-        /// </summary>
-        public void OnOpen()
-        {
-            if (!string.IsNullOrEmpty(BaudRate_SelectedComboBoxData.Value) &&
-                !string.IsNullOrEmpty(ParityBit_SelectedComboBoxData.Value) &&
-                !string.IsNullOrEmpty(StopBit_SelectedComboBoxData.Value) &&
-                !string.IsNullOrEmpty(Channel_SelectedComboBoxData.Value))
+            if (sendData != null)
             {
-                if (serialPortOperator == null)
+                if (BasicsData.SendWait)
                 {
-                    serialPortOperator = new SerialOperate(new SerialData.Basics()
+                    Task.Run(() =>
                     {
-                        BaudRate = int.Parse(BaudRate_SelectedComboBoxData.Value),
-                        DataBit = int.Parse(DataBit_SelectedComboBoxData.Value),
-                        ParityBit = (Parity)Enum.Parse(typeof(Parity), ParityBit_SelectedComboBoxData.Value),
-                        StopBit = (StopBits)Enum.Parse(typeof(StopBits), StopBit_SelectedComboBoxData.Value),
-                        PortName = Channel_SelectedComboBoxData.Value
+                        OperateResult operateResult = communication.SendWait(sendData);
+                        if (operateResult.RData is byte[])
+                        {
+                            operateResult.RData = operateResult.GetRData<byte[]>().ToHexString();
+                        }
+                        Output(operateResult.ToJson().JsonFormatting());
                     });
                 }
-                if (serialPortOperator.On().State)
-                {
-                    serialPortOperator.OnEvent += SerialPortOperator_OnEvent;
-                    LedIsOn = true;
-                    MessageBox.Show(LangsHelper.GetValue("msg6"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Information);
-                }
                 else
                 {
-                    MessageBox.Show(LangsHelper.GetValue("msg7"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
+                    OperateResult operateResult = communication.Send(sendData);
+                    Output(operateResult.ToJson().JsonFormatting());
                 }
             }
-            else
-            {
-                MessageBox.Show(LangsHelper.GetValue("msg3"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-            }
         }
-
         /// <summary>
-        /// 接收数据
+        /// 发送数据格式
+        /// 0 ASCII
+        /// 1 HEX
         /// </summary>
-        private void SerialPortOperator_OnEvent(object? sender, EventResult e)
+        public int DataFormat
         {
-            if (e.RData == null) return;
-            if (ReceiveDataFormat == 0)
-            {
-                ShowMessage(Encoding.Default.GetString(e.RData as byte[]));
-            }
-            else
-            {
-                ShowMessage(ByteTool.HexToStr(e.RData));
-            }
+            get => GetProperty(() => DataFormat);
+            set => SetProperty(() => DataFormat, value);
         }
 
-        public ICommand Open { get => new CommandX(OnOpen); }
-
         /// <summary>
-        /// 关闭串口
+        /// 发送的数据
         /// </summary>
-        public void OnClose()
+        public string SendData
         {
-            if (!LedIsOn) return;
-            if (serialPortOperator.Off().State)
-            {
-                LedIsOn = false;
-                serialPortOperator.OnEvent -= SerialPortOperator_OnEvent;
-                MessageBox.Show(LangsHelper.GetValue("msg8"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Information);
-            }
-            else
-            {
-                MessageBox.Show(LangsHelper.GetValue("msg9"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-            }
+            get => GetProperty(() => SendData);
+            set => SetProperty(() => SendData, value);
         }
-        public ICommand Close { get => new CommandX(OnClose); }
+
         /// <summary>
-        /// 输出标准消息
+        /// 接收数据
         /// </summary>
-        void ShowMessage(string Data, int Direction = 0)
+        private void Communication_OnEvent(object? sender, EventResult e)
         {
-            System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() =>
+            Output(e.Message.Replace("[", "[ ").Replace("]", " ] "));
+            if (e.State)
             {
-                if (ReceiveData?.Length > 10000)
+                if (InfoFormat == 0)
                 {
-                    ReceiveData = string.Empty;
-                }
-                string DirectionStr = Direction == 0 ? "Receive" : "Send";
-                if (Direction == 0)
-                {
-                    ReceiveData = $"[ {DateTime.Now.ToString("HH:mm:ss.fff")} ][ {DirectionStr} ]\r\n{Data}\r\n" + ReceiveData;
+                    Output($"[ {BasicsData.PortName} ] -> {Encoding.ASCII.GetString(e.GetRData<byte[]>())}", false);
                 }
                 else
                 {
-                    ReceiveData = $"[ {DateTime.Now.ToString("HH:mm:ss.fff")} ][ {DirectionStr} ]{Data}\r\n" + ReceiveData;
+                    Output($"[ {BasicsData.PortName} ] -> {e.GetRData<byte[]>().ToHexString()}", false);
                 }
-            }));
+            }
         }
     }
 }

+ 205 - 231
src/YSAI.Tool.Wpf/controllers/TcpClientController.cs

@@ -1,10 +1,13 @@
-using System.Text;
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Input;
 using YSAI.Core.communication.net.tcp.client;
-using YSAI.Core.Wpf;
 using YSAI.Core.Wpf.mvvm;
 using YSAI.Langs;
 using YSAI.Model.data;
 using YSAI.Unility;
+using static YSAI.Core.communication.net.tcp.client.TcpClientData;
 
 namespace YSAI.Tool.Wpf.controllers
 {
@@ -14,321 +17,292 @@ namespace YSAI.Tool.Wpf.controllers
         {
             //设置初始语言
             LangsHelper.SetLangs(LangsHelper.GetLangs());
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Tcp 客户端工具";
+            //配置文件名
+            FileName = typeof(TcpClientData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Visible;
+            //Hex是否显示
+            HexVisibility = Visibility.Visible;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
         }
 
+        #region 统一需要的数据
         /// <summary>
-        /// 服务器IP
+        /// 导出的文件名
         /// </summary>
-        public string ServerIP
+        private string FileName { get; set; }
+        /// <summary>
+        /// 工具标题
+        /// </summary>
+        public string ToolTitle
         {
-            get
-            {
-                return serverIP;
-            }
-            set
-            {
-                serverIP = value;
-                RaisePropertyChanged("ServerIP");
-            }
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
         }
-
-        private string serverIP = "127.0.0.1";
-
         /// <summary>
-        /// 服务器端口
+        /// 数据源
         /// </summary>
-        public string ServerPort
+        public Basics BasicsData
         {
-            get
-            {
-                return serverPort;
-            }
-            set
-            {
-                serverPort = value;
-                RaisePropertyChanged("ServerPort");
-            }
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
         }
 
-        private string serverPort = "8888";
+        /// <summary>
+        /// 导入基础数据命令
+        /// </summary>
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
 
         /// <summary>
-        /// 连接
+        /// 导入基础数据
         /// </summary>
-        public Command Connect
+        public void OnIncBasics()
         {
-            get
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
             {
-                if (connect == null)
-                    connect = new Command(new Action<object>
-                    (
-                        o =>
-                        {
-                            if (!string.IsNullOrEmpty(ServerIP) && !string.IsNullOrEmpty(ServerPort))
-                            {
-                                Client = new TcpClientOperate(new TcpClientData.Basics() { Ip = ServerIP, Port = int.Parse(ServerPort) });   //初始化端口
-                                Client.OnEvent += Client_OnEvent;
-                                if (Client.On().State)
-                                {
-                                    MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage1"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Information);
-                                }
-                                else
-                                {
-                                    Client = null;
-                                    MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage2"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                                }
-                            }
-                            else
-                            {
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage3"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                            }
-                        }
-                    ));
-                return connect;
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (BasicsData == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
             }
         }
 
-        private Command connect;
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
 
         /// <summary>
-        /// 断开连接
+        /// 导出基础数据
         /// </summary>
-        public Command OffConnect
+        public void OnExpBasics()
         {
-            get
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
             {
-                if (stop == null)
-                    stop = new Command(new Action<object>
-                    (
-                        o =>
-                        {
-                            if (Client == null)
-                            {
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage4"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                                return;
-                            }
-                            if (Client.Off().State)
-                            {
-                                Client.OnEvent -= Client_OnEvent;
-                                Client = null;
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage5"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Information);
-                            }
-                            else
-                            {
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage6"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                            }
-                        }
-                    ));
-                return stop;
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
             }
         }
 
-        private Command stop;
-
         /// <summary>
-        /// 清空消
+        /// 信息
         /// </summary>
-        public Command Clear
+        public string Info
         {
-            get
-            {
-                if (clear == null)
-                    clear = new Command(new Action<object>
-                    (o =>
-                    {
-                        ReceiveData = string.Empty;
-                    }));
-                return clear;
-            }
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
         }
 
-        private Command clear;
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
 
         /// <summary>
-        /// 发送数据格式
-        /// 0 ASCII
-        /// 1 HEX
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
         /// </summary>
-        public int SendDataFormat
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
         {
-            get
-            {
-                return sendDataFormat;
-            }
-            set
-            {
-                sendDataFormat = value;
-                RaisePropertyChanged("SendDataFormat");
-            }
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
         }
 
-        private int sendDataFormat = 0;
-
         /// <summary>
-        /// 发送的数据
+        /// 输出标准消息
         /// </summary>
-        public string SendData
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
         {
-            get
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
             {
-                return sendData;
-            }
-            set
-            {
-                sendData = value;
-                RaisePropertyChanged("SendData");
-            }
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
         }
-
-        private string sendData = string.Empty;
 
         /// <summary>
         /// 接收数据格式
         /// 0 ASCII
         /// 1 HEX
         /// </summary>
-        public int ReceiveDataFormat
+        public int InfoFormat
         {
-            get
-            {
-                return receiveDataFormat;
-            }
-            set
-            {
-                receiveDataFormat = value;
-                RaisePropertyChanged("ReceiveDataFormat");
-            }
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
         }
 
-        private int receiveDataFormat = 0;
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new CommandX(OnClear); }
 
         /// <summary>
-        /// 接收的数据
+        /// 清空信息
         /// </summary>
-        public string ReceiveData
+        public void OnClear()
         {
-            get
-            {
-                return receiveData;
-            }
-            set
-            {
-                receiveData = value;
-                RaisePropertyChanged("ReceiveData");
-            }
+            Info = string.Empty;
         }
 
-        private string receiveData = string.Empty;
+        #endregion 统一需要的数据
+
 
         /// <summary>
-        /// 发送
+        /// 通信
+        /// </summary>
+        private TcpClientOperate communication;
+
+        /// <summary>
+        /// 启动
         /// </summary>
-        public Command Send
+        public ICommand Start { get => new CommandX(OnStart); }
+        private void OnStart()
         {
-            get
+            communication = TcpClientOperate.Instance(BasicsData);
+            OperateResult operateResult = communication.On();
+            if (operateResult.State)
             {
-                if (send == null)
-                    send = new Command(new Action<object>
-                    (
-                        o =>
-                        {
-                            if (Client == null)
-                            {
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage4"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                                return;
-                            }
-                            if (string.IsNullOrEmpty(SendData))
-                            {
-                                MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage7"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Exclamation);
-                                return;
-                            }
-                            if (SendDataFormat.Equals(0))
-                            {
-                                if (!Client.Send(Encoding.ASCII.GetBytes(SendData)).State)
-                                {
-                                    ShowMessage($"[ {SendData} ][ {LangsHelper.GetValue("Fail")} ]", $"{ServerIP}:{ServerPort}", 1);
-                                }
-                            }
-                            else
-                            {
-                                if (ValidatorTool.IsHexadecimal(SendData))
-                                {
-                                    try
-                                    {
-                                        byte[] Data = (byte[])ByteTool.HexStringToByteArray(SendData);
-                                        if (!Client.Send(Data).State)
-                                        {
-                                            ShowMessage($"[ {SendData} ][ {LangsHelper.GetValue("Fail")} ]", $"{ServerIP}:{ServerPort}", 1);
-                                        }
-                                    }
-                                    catch (Exception ex)
-                                    {
-                                        MessageBox.Show(ex.Message, LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Warning);
-                                    }
-                                }
-                                else
-                                {
-                                    MessageBox.Show(LangsHelper.GetValue("SocketTcpClientToolMessage8"), LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Warning);
-                                }
-                            }
-                        }
-                    ));
-                return send;
+                communication.OnEvent -= Communication_OnEvent; ;
+                communication.OnEvent += Communication_OnEvent;
             }
+            Output(operateResult.ToJson().JsonFormatting());
         }
-
-        private Command send;
-
         /// <summary>
-        /// 客户端
+        /// 停止
         /// </summary>
-        private TcpClientOperate Client;
+        public ICommand Stop { get => new CommandX(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
 
-        private void Client_OnEvent(object? sender, EventResult e)
+        /// <summary>
+        /// 发送
+        /// </summary>
+        public ICommand Send { get => new CommandX(OnSend); }
+        private void OnSend()
         {
-            if (e.RData == null)
+            if (communication == null) return;
+            //发送的数据
+            byte[] sendData = null;
+            if (DataFormat.Equals(0))
             {
-                if (!string.IsNullOrEmpty(e.Message))
-                {
-                    System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() =>
-                    {
-                        MessageBox.Show(e.Message, LangsHelper.GetValue("Tips"), MessageBoxButton.OK, MessageBoxImage.Warning);
-                        OffConnect.Execute(OffConnect);
-                    }));
-                }
-                return;
+                sendData = Encoding.ASCII.GetBytes(SendData);
             }
-            if (ReceiveDataFormat == 0)
+            else
             {
-                ShowMessage(Encoding.Default.GetString(e.RData as byte[]), $"{ServerIP}:{ServerPort}");
+                if (ValidatorTool.IsHexadecimal(SendData))
+                {
+                    sendData = ByteTool.HexStringToByteArray(SendData);
+                }
+                else
+                {
+                    Output($"“{SendData}”不是有效的 Hex 数据");
+                }
             }
-            else
+            if (sendData != null)
             {
-                ShowMessage(ByteTool.HexToStr(e.RData), $"{ServerIP}:{ServerPort}");
+                if (BasicsData.SendWait)
+                {
+                    Task.Run(() =>
+                    {
+                        OperateResult operateResult = communication.SendWait(sendData);
+                        if (operateResult.RData is byte[])
+                        {
+                            operateResult.RData = operateResult.GetRData<byte[]>().ToHexString();
+                        }
+                        Output(operateResult.ToJson().JsonFormatting());
+                    });
+                }
+                else
+                {
+                    OperateResult operateResult = communication.Send(sendData);
+                    Output(operateResult.ToJson().JsonFormatting());
+                }
             }
         }
+        /// <summary>
+        /// 发送数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int DataFormat
+        {
+            get => GetProperty(() => DataFormat);
+            set => SetProperty(() => DataFormat, value);
+        }
 
         /// <summary>
-        /// 输出标准消息
+        /// 发送的数据
         /// </summary>
-        private void ShowMessage(string Data, string Address, int Direction = 0)
+        public string SendData
         {
-            System.Windows.Application.Current?.Dispatcher.Invoke(new Action(() =>
+            get => GetProperty(() => SendData);
+            set => SetProperty(() => SendData, value);
+        }
+
+        /// <summary>
+        /// 接收数据
+        /// </summary>
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message.Replace("[", "[ ").Replace("]", " ] "));
+            if (e.State)
             {
-                if (ReceiveData?.Length > 10000)
+                if (InfoFormat == 0)
                 {
-                    ReceiveData = string.Empty;
-                }
-                string DirectionStr = Direction == 0 ? "Receive" : "Send";
-                if (Direction == 0)
-                {
-                    ReceiveData = $"[ {DateTime.Now.ToString("HH:mm:ss.fff")} ][ {Address} ][ {DirectionStr} ]\r\n{Data}\r\n" + ReceiveData;
+                    Output($"[ {BasicsData.Ip}:{BasicsData.Port} ] -> {Encoding.ASCII.GetString(e.GetRData<byte[]>())}", false);
                 }
                 else
                 {
-                    ReceiveData = $"[ {DateTime.Now.ToString("HH:mm:ss.fff")} ][ {Address} ][ {DirectionStr} ]{Data}\r\n" + ReceiveData;
+                    Output($"[ {BasicsData.Ip}:{BasicsData.Port} ] -> {e.GetRData<byte[]>().ToHexString()}", false);
                 }
-            }));
+            }
         }
     }
 }

+ 3 - 2
src/YSAI.Tool.Wpf/controllers/TcpServiceController.cs

@@ -20,13 +20,14 @@ namespace YSAI.Tool.Wpf.controllers
         /// </summary>
         public TcpServiceController()
         {
-            DataGridData = new ObservableCollection<DataDataGrid.StructuralBody>();
             //设置初始语言
             LangsHelper.SetLangs(LangsHelper.GetLangs());
+            DataGridData = new ObservableCollection<DataDataGrid.StructuralBody>();
+
             //初始化基础数据
             BasicsData = new Basics();
             //工具标题
-            ToolTitle = "Tcp 服务工具";
+            ToolTitle = "Tcp 服务工具";
             //配置文件名
             FileName = typeof(TcpServiceData).Name;
             //Ascii是否显示

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

@@ -0,0 +1,305 @@
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Input;
+using YSAI.Core.communication.net.ws.client;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Unility;
+using static YSAI.Core.communication.net.ws.client.WsClientData;
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class WsClientController : NotifyObject
+    {
+        public WsClientController()
+        {
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Ws 客户端工具";
+            //配置文件名
+            FileName = typeof(WsClientData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Visible;
+            //Hex是否显示
+            HexVisibility = Visibility.Visible;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
+        }
+
+        #region 统一需要的数据
+        /// <summary>
+        /// 导出的文件名
+        /// </summary>
+        private string FileName { get; set; }
+        /// <summary>
+        /// 工具标题
+        /// </summary>
+        public string ToolTitle
+        {
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
+        }
+        /// <summary>
+        /// 数据源
+        /// </summary>
+        public Basics BasicsData
+        {
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
+        }
+
+        /// <summary>
+        /// 导入基础数据命令
+        /// </summary>
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (BasicsData == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
+        {
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new CommandX(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        #endregion 统一需要的数据
+
+
+        /// <summary>
+        /// 通信
+        /// </summary>
+        private WsClientOperate communication;
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public ICommand Start { get => new CommandX(OnStart); }
+        private void OnStart()
+        {
+            communication = WsClientOperate.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 CommandX(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        /// <summary>
+        /// 发送
+        /// </summary>
+        public ICommand Send { get => new CommandX(OnSend); }
+        private void OnSend()
+        {
+            if (communication == null) return;
+            //发送的数据
+            byte[] sendData = null;
+            if (DataFormat.Equals(0))
+            {
+                sendData = Encoding.ASCII.GetBytes(SendData);
+            }
+            else
+            {
+                if (ValidatorTool.IsHexadecimal(SendData))
+                {
+                    sendData = ByteTool.HexStringToByteArray(SendData);
+                }
+                else
+                {
+                    Output($"“{SendData}”不是有效的 Hex 数据");
+                }
+            }
+            if (sendData != null)
+            {
+                if (BasicsData.SendWait)
+                {
+                    Task.Run(() =>
+                    {
+                        OperateResult operateResult = communication.SendWait(sendData);
+                        if (operateResult.RData is byte[])
+                        {
+                            operateResult.RData = operateResult.GetRData<byte[]>().ToHexString();
+                        }
+                        Output(operateResult.ToJson().JsonFormatting());
+                    });
+                }
+                else
+                {
+                    OperateResult operateResult = communication.Send(sendData);
+                    Output(operateResult.ToJson().JsonFormatting());
+                }
+            }
+        }
+        /// <summary>
+        /// 发送数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int DataFormat
+        {
+            get => GetProperty(() => DataFormat);
+            set => SetProperty(() => DataFormat, value);
+        }
+
+        /// <summary>
+        /// 发送的数据
+        /// </summary>
+        public string SendData
+        {
+            get => GetProperty(() => SendData);
+            set => SetProperty(() => SendData, value);
+        }
+
+        /// <summary>
+        /// 接收数据
+        /// </summary>
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message.Replace("[", "[ ").Replace("]", " ] "));
+            if (e.State)
+            {
+                if (InfoFormat == 0)
+                {
+                    Output($"[ {BasicsData.Host} ] -> {Encoding.ASCII.GetString(e.GetRData<byte[]>())}", false);
+                }
+                else
+                {
+                    Output($"[ {BasicsData.Host} ] -> {e.GetRData<byte[]>().ToHexString()}", false);
+                }
+            }
+        }
+    }
+}

+ 424 - 0
src/YSAI.Tool.Wpf/controllers/WsServiceController.cs

@@ -0,0 +1,424 @@
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using YSAI.Core.communication.net.ws.service;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Unility;
+using static YSAI.Core.communication.net.ws.service.WsServiceData;
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class WsServiceController : NotifyObject
+    {
+        public WsServiceController()
+        {
+
+            DataGridData = new ObservableCollection<DataDataGrid.StructuralBody>();
+
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Ws 服务端工具";
+            //配置文件名
+            FileName = typeof(WsServiceData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Visible;
+            //Hex是否显示
+            HexVisibility = Visibility.Visible;
+            //信息格式;  0 ASCII ; 1 HEX
+            InfoFormat = 0;
+        }
+
+        #region 统一需要的数据
+        /// <summary>
+        /// 导出的文件名
+        /// </summary>
+        private string FileName { get; set; }
+        /// <summary>
+        /// 工具标题
+        /// </summary>
+        public string ToolTitle
+        {
+            get => GetProperty(() => ToolTitle);
+            set => SetProperty(() => ToolTitle, value);
+        }
+        /// <summary>
+        /// 数据源
+        /// </summary>
+        public Basics BasicsData
+        {
+            get => GetProperty(() => BasicsData);
+            set => SetProperty(() => BasicsData, value);
+        }
+
+        /// <summary>
+        /// 导入基础数据命令
+        /// </summary>
+        public ICommand IncBasics { get => new CommandX(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (BasicsData == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new CommandX(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => GetProperty(() => Info);
+            set => SetProperty(() => Info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new CommandX<System.Windows.Controls.TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private void Output(string Data, bool IsDate = true)
+        {
+            System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+            {
+                if (Info?.Length > 5000)
+                {
+                    Info = string.Empty;
+                }
+                if (IsDate)
+                {
+                    Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                }
+                else
+                {
+                    Info += $"{Data}\r\n";
+                }
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new CommandX(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        #endregion 统一需要的数据
+
+
+        /// <summary>
+        /// 通信
+        /// </summary>
+        private WsServiceOperate communication;
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public ICommand Start { get => new CommandX(OnStart); }
+        private void OnStart()
+        {
+            communication = WsServiceOperate.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 CommandX(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+            DataGridData.Clear();
+        }
+
+        /// <summary>
+        /// 发送
+        /// </summary>
+        public ICommand Send { get => new CommandX(OnSend); }
+        private void OnSend()
+        {
+            if (communication == null) return;
+            //发送的数据
+            byte[] sendData = null;
+            if (DataFormat.Equals(0))
+            {
+                sendData = Encoding.ASCII.GetBytes(SendData);
+            }
+            else
+            {
+                if (ValidatorTool.IsHexadecimal(SendData))
+                {
+                    sendData = ByteTool.HexStringToByteArray(SendData);
+                }
+                else
+                {
+                    Output($"“{SendData}”不是有效的 Hex 数据");
+                }
+            }
+            if (sendData != null)
+            {
+                if (MassData)
+                {
+                    OperateResult operateResult = communication.Send(sendData, null);
+                    Output(operateResult.ToJson().JsonFormatting());
+                }
+                else
+                {
+                    if (CheckedLineData != null && !string.IsNullOrEmpty(CheckedLineData.IPENDPORT))
+                    {
+                        OperateResult operateResult = communication.Send(sendData, new string[] { CheckedLineData.IPENDPORT });
+                        Output(operateResult.ToJson().JsonFormatting());
+                    }
+                    else
+                    {
+                        Output("请选择一个已连接的客户端");
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 发送数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int DataFormat
+        {
+            get => GetProperty(() => DataFormat);
+            set => SetProperty(() => DataFormat, value);
+        }
+
+        /// <summary>
+        /// 发送的数据
+        /// </summary>
+        public string SendData
+        {
+            get => GetProperty(() => SendData);
+            set => SetProperty(() => SendData, value);
+        }
+
+        /// <summary>
+        /// 接收数据
+        /// </summary>
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message.Replace("[", "[ ").Replace("]", " ] "));
+            ClientMessage? message = e.GetRData<ClientMessage>();
+            if (message == null)
+            {
+                return;
+            }
+            string[] ipport;
+            switch (message.Step)
+            {
+                case Steps.客户端连接:
+                    ipport = message.IpPort.Split(':');
+                    System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                    {
+                        DataGridData.Add(new DataDataGrid.StructuralBody() { IP = ipport[0], Port = ipport[1], IPENDPORT = message.IpPort });
+                    });
+                    break;
+                case Steps.客户端断开:
+                    System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                    {
+                        for (int i = 0; i < DataGridData.Count; i++)
+                        {
+                            if (DataGridData[i].IPENDPORT.Equals(message.IpPort))
+                            {
+                                DataGridData.RemoveAt(i);
+                                continue;
+                            }
+                        }
+                    });
+                    break;
+                case Steps.消息接收:
+                    if (InfoFormat == 0)
+                    {
+                        Output($"[ {message.IpPort} ] -> {Encoding.ASCII.GetString(message.Data)}", false);
+                    }
+                    else
+                    {
+                        Output($"[ {message.IpPort} ] -> {message.Data.ToHexString()}", false);
+                    }
+                    break;
+            }
+        }
+        /// <summary>
+        /// 群发数据
+        /// </summary>
+        public bool MassData
+        {
+            get => GetProperty(() => MassData);
+            set => SetProperty(() => MassData, value);
+        }
+
+        /// <summary>
+        /// 表格数据
+        /// </summary>
+        public ObservableCollection<DataDataGrid.StructuralBody> DataGridData
+        {
+            get => GetProperty(() => DataGridData);
+            set => SetProperty(() => DataGridData, value);
+        }
+        /// <summary>
+        /// 选中的行数据
+        /// </summary>
+        public DataDataGrid.StructuralBody CheckedLineData = new DataDataGrid.StructuralBody();
+
+        /// <summary>
+        /// 表格数据选中触发
+        /// </summary>
+        public ICommand GridDataSelectionChanged { get => new CommandX<SelectionChangedEventArgs>(OnGridDataSelectionChanged); }
+        /// <summary>
+        /// 触发事件
+        /// </summary>
+        /// <param name="e"></param>
+        private void OnGridDataSelectionChanged(SelectionChangedEventArgs e)
+        {
+            CheckedLineData = (e.Source as DataGrid).SelectedItem as DataDataGrid.StructuralBody;
+        }
+
+        public class DataDataGrid
+        {
+            /// <summary>
+            /// DataGrid结构体
+            /// </summary>
+            public class StructuralBody : NotifyObject
+            {
+                public string IP
+                {
+                    get
+                    {
+                        return ip;
+                    }
+                    set
+                    {
+                        if (value != null && !value.Equals(ip))
+                        {
+                            ip = value;
+                            RaisePropertyChanged("IP");
+                        }
+                    }
+                }
+
+                private string ip;
+
+                public string Port
+                {
+                    get
+                    {
+                        return port;
+                    }
+                    set
+                    {
+                        if (value != null && !value.Equals(port))
+                        {
+                            port = value;
+                            RaisePropertyChanged("Port");
+                        }
+                    }
+                }
+
+                private string port;
+
+                /// <summary>
+                /// 地址与端口
+                /// </summary>
+                public string IPENDPORT { get; set; }
+            }
+        }
+
+    }
+}

+ 308 - 14
src/YSAI.Tool.Wpf/views/Serial.xaml

@@ -5,19 +5,312 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
              xmlns:cl="clr-namespace:YSAI.Core.Wpf.controls.ledgauge;assembly=YSAI.Core.Wpf"
-             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
-             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
              xmlns:lang="http://wpflocalizeextension.codeplex.com"
              lang:LocalizeDictionary.DesignCulture="zh"
              lang:ResxLocalizationProvider.DefaultAssembly="YSAI.Langs"
-             lang:ResxLocalizationProvider.DefaultDictionary="Lang"> 
+             lang:ResxLocalizationProvider.DefaultDictionary="Lang"
+             
+             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:SerialController />
     </UserControl.DataContext>
 
+
+    <!--资源加载-->
     <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeDataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                    <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="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="Height" Value="25"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" MinWidth="600">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid Grid.Row="0" Grid.Column="1"  Margin="0,-40,0,0">
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
+                                    <btn:ButtonControl  Grid.Column="5"  Width="80"   Command="{Binding Start}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource Open}"
+                                           Content="打开"/>
+
+                                    <btn:ButtonControl  Grid.Column="6"  Width="80"  Command="{Binding Stop}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource CloseBase}"
+                                           Content="关闭"/>
+                                </StackPanel>
+                            </Grid>
+                            <!--发送区域-->
+                            <Grid Grid.Row="1" Grid.Column="1">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition/>
+                                    <RowDefinition/>
+                                </Grid.RowDefinitions>
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30">
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <btn:ButtonControl  Grid.Column="3"  Width="80"  Command="{Binding Send}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+                                                            IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                            BorderBrush="{DynamicResource Control.Border.Color}"
+                                                            IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                            Foreground="{DynamicResource Font.Content.Foreground}"
+                                                            Icon="{DynamicResource Send}"
+                                                            Content="发送"/>
+                                </StackPanel>
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Grid.Row="1" Grid.ColumnSpan="8" Width="auto" Margin="0,0,0,0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid>
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto"/>
+                                                    <ColumnDefinition Width="*"/>
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Data}" Width="14" />
+                                                <TextBlock Text="数据" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+                                    <TextBox  Padding="5" Style="{DynamicResource TextBoxStyle2}" Height="230" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Text="{Binding SendData}" />
+                                </GroupBox>
+                            </Grid>
+                        </Grid>
+
+
+
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+                    </GroupBox>
+                    <!--信息-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,5,0,0"  Grid.Row="1">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Info}" Width="14" />
+                                    <TextBlock Text="信息" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition />
+                            </Grid.RowDefinitions>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,-40,0,0">
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <btn:ButtonControl  Width="80"  Command="{Binding Clear}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+Foreground="{DynamicResource Font.Content.Foreground}"
+Icon="{DynamicResource Clear}"
+Content="清空"/>
+                            </StackPanel>
+                            <TextBox Grid.Row="1" Padding="5" Grid.ColumnSpan="2" Style="{DynamicResource TextBoxStyle2}"  FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"  Text="{Binding Info}" >
+                                <i:Interaction.Triggers>
+                                    <i:EventTrigger EventName="TextChanged">
+                                        <mvvm:EventCommand  Command="{Binding Info_TextChanged}" />
+                                    </i:EventTrigger>
+                                </i:Interaction.Triggers>
+                            </TextBox>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
+            </Grid>
+        </GroupBox>
+    </Border>
+
+
+
+    <!--#region 暂不使用 -->
+    <!--<UserControl.Resources>
         <ResourceDictionary>
             <cs:CheckConverter x:Key="CheckConverter" />
             <ResourceDictionary.MergedDictionaries>
@@ -60,14 +353,14 @@
                     <RowDefinition Height="260" />
                     <RowDefinition Height="400" />
                 </Grid.RowDefinitions>
-                <!--设置区域-->
+                --><!--设置区域--><!--
                 <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="0" Grid.Column="0" Margin="5"  Width="835">
                     <GroupBox.Header>
                         <Border>
                             <TextBlock Text="{lang:Loc SetRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
                         </Border>
                     </GroupBox.Header>
-                    <!--设置区域-->
+                    --><!--设置区域--><!--
                     <Grid>
                         <Grid.RowDefinitions>
                             <RowDefinition />
@@ -141,7 +434,7 @@
                                                 Foreground="{DynamicResource Font.Content.Foreground}"
                                                 Icon="{DynamicResource CloseBase}"
                                                 Content="{lang:Loc Close}"
-                                                CornerRadius="{DynamicResource WindowCornerRadius}" />  
+                                                CornerRadius="{DynamicResource WindowCornerRadius}" />
 
                             <btn:ButtonControl  Grid.Column="1"  Width="80"  Margin="0,0,10,0" Command="{Binding Open}" HorizontalAlignment="Center" VerticalAlignment="Center"
                                                 IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
@@ -150,13 +443,13 @@
                                                 Foreground="{DynamicResource Font.Content.Foreground}"
                                                 Icon="{DynamicResource Open}"
                                                 Content="{lang:Loc Open}"
-                                                CornerRadius="{DynamicResource WindowCornerRadius}" />  
+                                                CornerRadius="{DynamicResource WindowCornerRadius}" />
+
 
-                            
                         </Grid>
                     </Grid>
                 </GroupBox>
-                <!--发送区域-->
+                --><!--发送区域--><!--
                 <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1" Margin="5" Width="835">
                     <GroupBox.Header>
                         <Border>
@@ -180,7 +473,7 @@
                             <ColumnDefinition  Width="55" />
                             <ColumnDefinition  Width="90" />
                         </Grid.ColumnDefinitions>
-                      
+
                         <Label Content="{lang:Loc [SendMode]}" Grid.Column="6" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center" HorizontalAlignment="Right"  Margin="0,0,10,0" />
                         <RadioButton IsChecked="{Binding SendDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Grid.Column="7" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Center" />
                         <RadioButton IsChecked="{Binding SendDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}" Grid.Column="8"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Center" />
@@ -192,7 +485,7 @@
                                              Foreground="{DynamicResource Font.Content.Foreground}"
                                              Icon="{DynamicResource Send}"
                                              Content="{lang:Loc Send}"
-                                             CornerRadius="{DynamicResource WindowCornerRadius}" /> 
+                                             CornerRadius="{DynamicResource WindowCornerRadius}" />
                         <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1"  Grid.ColumnSpan="10">
                             <GroupBox.Header>
                                 <Border>
@@ -203,7 +496,7 @@
                         </GroupBox>
                     </Grid>
                 </GroupBox>
-                <!--接收数据区域-->
+                --><!--接收数据区域--><!--
                 <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="2" Margin="5" Width="835">
                     <GroupBox.Header>
                         <Border>
@@ -232,7 +525,7 @@
                                              Foreground="{DynamicResource Font.Content.Foreground}"
                                              Icon="{DynamicResource Clear}"
                                              Content="{lang:Loc Empty}"
-                                             CornerRadius="{DynamicResource WindowCornerRadius}" /> 
+                                             CornerRadius="{DynamicResource WindowCornerRadius}" />
                         <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1"  Grid.ColumnSpan="7">
                             <GroupBox.Header>
                                 <Border>
@@ -245,5 +538,6 @@
                 </GroupBox>
             </Grid>
         </GroupBox>
-    </Grid>
+    </Grid>-->
+    <!--#endregion-->
 </UserControl>

+ 263 - 144
src/YSAI.Tool.Wpf/views/TcpClient.xaml

@@ -4,18 +4,32 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:YSAI.Tool.Wpf.views"
-             xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
-             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
              xmlns:lang="http://wpflocalizeextension.codeplex.com"
             lang:LocalizeDictionary.DesignCulture="zh"
             lang:ResxLocalizationProvider.DefaultAssembly="YSAI.Langs"
             lang:ResxLocalizationProvider.DefaultDictionary="Lang"
-             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf">
+             
+            xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+            xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+            xmlns:pt="http://propertytools.org/wpf"
+            xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+            xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+            xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+            xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+            Background="{DynamicResource ContentBackgroundPicture}">    
     <UserControl.DataContext>
         <c:TcpClientController />
     </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
     <UserControl.Resources>
         <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
             <cs:CheckConverter x:Key="CheckConverter" />
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
@@ -29,160 +43,265 @@
                 <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeDataGrid.xaml" />
                 <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
                 <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
     </UserControl.Resources>
-    <Grid Width="620" Height="720">
-        <Border  CornerRadius="{DynamicResource WindowCornerRadius}"  Background="{DynamicResource WindowContentBackground}">
-            <Border.Effect>
-                <BlurEffect Radius="0" />
-            </Border.Effect>
-        </Border>
-        <GroupBox Style="{StaticResource GroupBoxTab}" Width="auto">
+
+    <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 Background="Transparent">
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
                             <ColumnDefinition Width="*" />
                         </Grid.ColumnDefinitions>
-                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Communication}" Width="14" />
-                        <TextBlock Text="TCP 客户端工具" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                        <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.RowDefinitions>
-                    <RowDefinition Height="70" />
-                    <RowDefinition Height="200" />
-                    <RowDefinition  Height="400" />
-                </Grid.RowDefinitions>
-                <!--设置区域-->
-                <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="0" Margin="5">
-                    <GroupBox.Header>
-                        <Border>
-                            <TextBlock Text="{lang:Loc SetRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
-                        </Border>
-                    </GroupBox.Header>
-                    <!--设置区域-->
-                    <Grid>
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="auto" />
-                            <ColumnDefinition Width="140" />
-                            <ColumnDefinition Width="auto" />
-                            <ColumnDefinition Width="80" />
-                            <ColumnDefinition Width="*" />
-                            <ColumnDefinition Width="auto" />
-                            <ColumnDefinition  Width="auto" />
-                        </Grid.ColumnDefinitions>
-                        <Label Content="{lang:Loc ServerIP}" Grid.Column="0" Foreground="{DynamicResource Font.Content.Foreground}" HorizontalAlignment="Right" VerticalAlignment="Center" />
-                        <TextBox Text="{Binding ServerIP,UpdateSourceTrigger=PropertyChanged}" Margin="0,0,5,0" Grid.Column="1" Style="{StaticResource TextBoxStyle2}" Height="30"  Foreground="{DynamicResource Font.Content.Foreground}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
-                        <Label Content="{lang:Loc ServerPort}" Grid.Column="2" Foreground="{DynamicResource Font.Content.Foreground}" HorizontalAlignment="Right" VerticalAlignment="Center" />
-                        <TextBox Text="{Binding ServerPort,UpdateSourceTrigger=PropertyChanged}" Margin="0,0,5,0" Grid.Column="3" Style="{StaticResource TextBoxStyle2}" Height="30"  Foreground="{DynamicResource Font.Content.Foreground}" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
-
-                        <btn:ButtonControl  Grid.Column="5"  Width="90"  Margin="0,0,5,0" Command="{Binding Connect}" HorizontalAlignment="Right" 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 ConnectBase}"
-                                      Content="{lang:Loc Connect}"
-                                      CornerRadius="{DynamicResource WindowCornerRadius}" />
-
-                        <btn:ButtonControl  Grid.Column="6"  Width="90"  Margin="0,0,10,0" Command="{Binding OffConnect}" HorizontalAlignment="Right" 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 OffConnect}"
-                                      Content="{lang:Loc Break}"
-                                      CornerRadius="{DynamicResource WindowCornerRadius}" />    
-                        
-                    </Grid>
-                </GroupBox>
-                <!--发送区域-->
-                <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1" Margin="5">
-                    <GroupBox.Header>
-                        <Border>
-                            <TextBlock Text="{lang:Loc SendRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
-                        </Border>
-                    </GroupBox.Header>
-                    <Grid>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="45" />
-                            <RowDefinition />
-                        </Grid.RowDefinitions>
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition Width="65" />
-                            <ColumnDefinition Width="150" />
-                            <ColumnDefinition Width="78" />
-                            <ColumnDefinition Width="80" />
-                            <ColumnDefinition Width="55" />
-                            <ColumnDefinition Width="60" />
-                            <ColumnDefinition  Width="auto" />
-                        </Grid.ColumnDefinitions>
-                        <Label Content="{lang:Loc [SendMode]}" Grid.Column="2" Grid.ColumnSpan="2" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center" HorizontalAlignment="Right"  Margin="0,0,10,0" />
-                        <RadioButton IsChecked="{Binding SendDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}"  Grid.Column="4" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Center" />
-                        <RadioButton IsChecked="{Binding SendDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}" Grid.Column="5"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Center" />
-
-                        <btn:ButtonControl   Width="80"  Command="{Binding Send}" HorizontalAlignment="Right" VerticalAlignment="Center"  Margin="0,0,10,0" Grid.Column="6" 
-                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
-                          BorderBrush="{DynamicResource Control.Border.Color}"
-                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
-                          Foreground="{DynamicResource Font.Content.Foreground}"
-                          Icon="{DynamicResource Send}"
-                          Content="{lang:Loc Send}"
-                          CornerRadius="{DynamicResource WindowCornerRadius}" />
-                        <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1"  Grid.ColumnSpan="7">
-                            <GroupBox.Header>
-                                <Border>
-                                    <TextBlock Text="{lang:Loc DataRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
-                                </Border>
-                            </GroupBox.Header>
-                            <TextBox Style="{DynamicResource TextBoxStyle2}" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Margin="5" Text="{Binding SendData,UpdateSourceTrigger=PropertyChanged}" Height="auto" Width="545" />
-                        </GroupBox>
-                    </Grid>
-                </GroupBox>
-                <!--接收区域-->
-                <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="2" Margin="5">
-                    <GroupBox.Header>
-                        <Border>
-                            <TextBlock Text="{lang:Loc ReceptionRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
-                        </Border>
-                    </GroupBox.Header>
-                    <Grid>
-                        <Grid.RowDefinitions>
-                            <RowDefinition Height="45" />
-                            <RowDefinition />
-                        </Grid.RowDefinitions>
-                        <Grid.ColumnDefinitions>
-                            <ColumnDefinition />
-                            <ColumnDefinition Width="55" />
-                            <ColumnDefinition  Width="55" />
-                            <ColumnDefinition  Width="90" />
-                        </Grid.ColumnDefinitions>
-                        <Label Content="{lang:Loc DisplayMode}" Grid.Column="0" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center" HorizontalAlignment="Right"  Margin="0,0,10,0" />
-                        <RadioButton IsChecked="{Binding ReceiveDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Grid.Column="1" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Center" />
-                        <RadioButton IsChecked="{Binding ReceiveDataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}" Grid.Column="2"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Center" />
-                        <btn:ButtonControl  Grid.Column="3"  Width="80"  Margin="0,0,10,0" Command="{Binding Empty}" HorizontalAlignment="Left" 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 Clear}"
-                                              Content="{lang:Loc Empty}"
-                                              CornerRadius="{DynamicResource WindowCornerRadius}" />    
-                        <GroupBox Style="{StaticResource GroupBoxStyle}" Grid.Row="1"  Grid.ColumnSpan="7">
-                            <GroupBox.Header>
-                                <Border>
-                                    <TextBlock Text="{lang:Loc DataRegion}" Foreground="{DynamicResource Font.Head.Foreground}" />
-                                </Border>
-                            </GroupBox.Header>
-                            <TextBox Style="{DynamicResource TextBoxStyle2}" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Margin="5" Text="{Binding ReceiveData,UpdateSourceTrigger=PropertyChanged}" Height="auto" Width="545" />
-                        </GroupBox>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                    <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="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="Height" Value="25"/>
+                                    <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>
-                </GroupBox>
+                </Grid>
+
+
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" MinWidth="600">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid Grid.Row="0" Grid.Column="1"  Margin="0,-40,0,0">
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
+                                    <btn:ButtonControl  Grid.Column="5"  Width="80"   Command="{Binding Start}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource Open}"
+                                           Content="打开"/>
+
+                                    <btn:ButtonControl  Grid.Column="6"  Width="80"  Command="{Binding Stop}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource CloseBase}"
+                                           Content="关闭"/>
+                                </StackPanel>
+                            </Grid>
+                            <!--发送区域-->
+                            <Grid Grid.Row="1" Grid.Column="1">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition/>
+                                    <RowDefinition/>
+                                </Grid.RowDefinitions>
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30">
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <btn:ButtonControl  Grid.Column="3"  Width="80"  Command="{Binding Send}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+                                                            IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                            BorderBrush="{DynamicResource Control.Border.Color}"
+                                                            IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                            Foreground="{DynamicResource Font.Content.Foreground}"
+                                                            Icon="{DynamicResource Send}"
+                                                            Content="发送"/>
+                                </StackPanel>
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Grid.Row="1" Grid.ColumnSpan="8" Width="auto" Margin="0,0,0,0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid>
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto"/>
+                                                    <ColumnDefinition Width="*"/>
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Data}" Width="14" />
+                                                <TextBlock Text="数据" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+                                    <TextBox  Padding="5" Style="{DynamicResource TextBoxStyle2}" Height="230" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Text="{Binding SendData}" />
+                                </GroupBox>
+                            </Grid>
+                        </Grid>
+
+
+
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+                    </GroupBox>
+                    <!--信息-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,5,0,0"  Grid.Row="1">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Info}" Width="14" />
+                                    <TextBlock Text="信息" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition />
+                            </Grid.RowDefinitions>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,-40,0,0">
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <btn:ButtonControl  Width="80"  Command="{Binding Clear}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+Foreground="{DynamicResource Font.Content.Foreground}"
+Icon="{DynamicResource Clear}"
+Content="清空"/>
+                            </StackPanel>
+                            <TextBox Grid.Row="1" Padding="5" Grid.ColumnSpan="2" Style="{DynamicResource TextBoxStyle2}"  FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"  Text="{Binding Info}" >
+                                <i:Interaction.Triggers>
+                                    <i:EventTrigger EventName="TextChanged">
+                                        <mvvm:EventCommand  Command="{Binding Info_TextChanged}" />
+                                    </i:EventTrigger>
+                                </i:Interaction.Triggers>
+                            </TextBox>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
             </Grid>
         </GroupBox>
-    </Grid>
+    </Border>
 </UserControl>

+ 302 - 0
src/YSAI.Tool.Wpf/views/WsClient.xaml

@@ -0,0 +1,302 @@
+<UserControl x:Class="YSAI.Tool.Wpf.views.WsClient"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:YSAI.Tool.Wpf.views"
+             xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+             xmlns:pt="http://propertytools.org/wpf"
+             xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+             Background="{DynamicResource ContentBackgroundPicture}">
+    <UserControl.DataContext>
+        <c:WsClientController />
+    </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeDataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0" Margin="0,0,5,0" Width="500">
+                    <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="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="Height" Value="25"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" MinWidth="600">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid Grid.Row="0" Grid.Column="1"  Margin="0,-40,0,0">
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" >
+                                    <btn:ButtonControl  Grid.Column="5"  Width="80"   Command="{Binding Start}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource Open}"
+                                           Content="打开"/>
+
+                                    <btn:ButtonControl  Grid.Column="6"  Width="80"  Command="{Binding Stop}" HorizontalAlignment="Right" VerticalAlignment="Center" BorderThickness="1,0,0,0"
+                                           IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                           BorderBrush="{DynamicResource Control.Border.Color}"
+                                           IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                           Foreground="{DynamicResource Font.Content.Foreground}"
+                                           Icon="{DynamicResource CloseBase}"
+                                           Content="关闭"/>
+                                </StackPanel>
+                            </Grid>
+                            <!--发送区域-->
+                            <Grid Grid.Row="1" Grid.Column="1">
+                                <Grid.RowDefinitions>
+                                    <RowDefinition/>
+                                    <RowDefinition/>
+                                </Grid.RowDefinitions>
+                                <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30">
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <RadioButton ToolTip="发送方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding DataFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                    <btn:ButtonControl  Grid.Column="3"  Width="80"  Command="{Binding Send}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+                                                            IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                                            BorderBrush="{DynamicResource Control.Border.Color}"
+                                                            IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                                            Foreground="{DynamicResource Font.Content.Foreground}"
+                                                            Icon="{DynamicResource Send}"
+                                                            Content="发送"/>
+                                </StackPanel>
+                                <GroupBox Style="{StaticResource GroupBoxTab}" Grid.Row="1" Grid.ColumnSpan="8" Width="auto" Margin="0,0,0,0">
+                                    <GroupBox.Header>
+                                        <StackPanel Orientation="Horizontal">
+                                            <Grid>
+                                                <Grid.ColumnDefinitions>
+                                                    <ColumnDefinition Width="auto"/>
+                                                    <ColumnDefinition Width="*"/>
+                                                </Grid.ColumnDefinitions>
+                                                <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Data}" Width="14" />
+                                                <TextBlock Text="数据" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                            </Grid>
+                                        </StackPanel>
+                                    </GroupBox.Header>
+                                    <TextBox  Padding="5" Style="{DynamicResource TextBoxStyle2}" Height="230" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible" Text="{Binding SendData}" />
+                                </GroupBox>
+                            </Grid>
+                        </Grid>
+
+
+
+
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+                    </GroupBox>
+                    <!--信息-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0,5,0,0"  Grid.Row="1">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto"/>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Info}" Width="14" />
+                                    <TextBlock Text="信息" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" VerticalAlignment="Center"/>
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto" />
+                                <RowDefinition />
+                            </Grid.RowDefinitions>
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition />
+                                <ColumnDefinition Width="auto" />
+                            </Grid.ColumnDefinitions>
+                            <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,-40,0,0">
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0"  Visibility="{Binding AsciiVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=0}" Style="{StaticResource RadioButtonStyle}" Content="ASCII" VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <RadioButton ToolTip="显示方式" Margin="0,0,15,0" Visibility="{Binding HexVisibility}" IsChecked="{Binding InfoFormat,Mode=TwoWay,Converter={StaticResource CheckConverter},ConverterParameter=1}"  Style="{StaticResource RadioButtonStyle}" Content="Hex"  VerticalAlignment="Center" HorizontalAlignment="Right" />
+                                <btn:ButtonControl  Width="80"  Command="{Binding Clear}" HorizontalAlignment="Right" VerticalAlignment="Center"  BorderThickness="1,0,0,0"
+IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+Foreground="{DynamicResource Font.Content.Foreground}"
+Icon="{DynamicResource Clear}"
+Content="清空"/>
+                            </StackPanel>
+                            <TextBox Grid.Row="1" Padding="5" Grid.ColumnSpan="2" Style="{DynamicResource TextBoxStyle2}"  FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Visible"  Text="{Binding Info}" >
+                                <i:Interaction.Triggers>
+                                    <i:EventTrigger EventName="TextChanged">
+                                        <mvvm:EventCommand  Command="{Binding Info_TextChanged}" />
+                                    </i:EventTrigger>
+                                </i:Interaction.Triggers>
+                            </TextBox>
+                        </Grid>
+                    </GroupBox>
+                </Grid>
+            </Grid>
+        </GroupBox>
+    </Border>
+</UserControl>

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

+ 10 - 0
src/YSAI.Tool.Wpf/views/WsService.xaml

@@ -0,0 +1,10 @@
+<UserControl x:Class="YSAI.Tool.Wpf.views.WsService"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             xmlns:local="clr-namespace:YSAI.Tool.Wpf.views">
+    <Grid>
+            
+    </Grid>
+</UserControl>

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

+ 10 - 10
src/YSAI.Ver.Manage.Tool/Program.cs

@@ -39,16 +39,16 @@ List<string> strings = new List<string>
     //"YSAI.Netty",
     //"YSAI.RabbitMQ",
 
-    //"YSAI.AllenBradley",
-    //"YSAI.Beckhoff",
-    //"YSAI.Can",
-    //"YSAI.DB",
-    //"YSAI.Mewtocol",
-    //"YSAI.Mitsubishi",
-    //"YSAI.Modbus",
-    //"YSAI.Omron",
-    //"YSAI.Opc",
-    //"YSAI.Siemens",
+    "YSAI.AllenBradley",
+    "YSAI.Beckhoff",
+    "YSAI.Can",
+    "YSAI.DB",
+    "YSAI.Mewtocol",
+    "YSAI.Mitsubishi",
+    "YSAI.Modbus",
+    "YSAI.Omron",
+    "YSAI.Opc",
+    "YSAI.Siemens",
 #endif
 };