Browse Source

1. mqtt 服务端问题修改
2. mqtt 客户端新增断开事件
3. mqtt 客户端服务端工具改造完成
4. 新增采集、转发工具模版,更快的集成新的驱动

Shun 2 years ago
parent
commit
b84494a149

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

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

+ 35 - 14
src/YSAI.Mqtt/client/MqttClientOperate.cs

@@ -63,16 +63,11 @@ namespace YSAI.Mqtt.client
         public MqttClientOperate(MqttClientData.Basics param)
         {
             this.mqttClientData = param;
+        }
+
 
-            //工厂模式获取连接客户端对象
-            mqttClient = new MqttFactory().CreateMqttClient() as MQTTnet.Client.MqttClient;
 
-            //客户端支持 Connected、Disconnected 和 ApplicationMessageReceived 事件,
-            //用来处理客户端与服务端连接、客户端从服务端断开以及客户端收到消息的事情。
 
-            //消息(异步)
-            mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
-        }
 
         public MqttClientOperate()
         { }
@@ -92,7 +87,19 @@ namespace YSAI.Mqtt.client
         #endregion 属性
 
         #region 私有函数
-
+        /// <summary>
+        /// 服务端断开
+        /// </summary>
+        /// <param name="arg"></param>
+        /// <returns></returns>
+        private Task MqttClient_DisconnectedAsync(MqttClientDisconnectedEventArgs arg)
+        {
+            return Task.Run(() =>
+            {
+                OnEventHandler(this, new EventResult(false, $"与服务端断开连接", ResultType.Dynamic));
+                Off();
+            });
+        }
         /// <summary>
         /// 消息事件
         /// </summary>
@@ -165,7 +172,7 @@ namespace YSAI.Mqtt.client
             string SN = Depart("Publish");
             try
             {
-                if (!mqttClient.IsConnected)
+                if (mqttClient == null || !mqttClient.IsConnected)
                 {
                     return Break(SN, false, "未连接");
                 }
@@ -232,7 +239,7 @@ namespace YSAI.Mqtt.client
             string SN = Depart("AddSubscribe");
             try
             {
-                if (!mqttClient.IsConnected)
+                if (mqttClient == null || !mqttClient.IsConnected)
                 {
                     return Break(SN, false, "未连接");
                 }
@@ -267,7 +274,7 @@ namespace YSAI.Mqtt.client
             string SN = Depart("RemoveSubscribe");
             try
             {
-                if (!mqttClient.IsConnected)
+                if (mqttClient == null || !mqttClient.IsConnected)
                 {
                     return Break(SN, false, "未连接");
                 }
@@ -292,10 +299,23 @@ namespace YSAI.Mqtt.client
             string SN = Depart("On");
             try
             {
-                if (mqttClient.IsConnected)
+                if (mqttClient != null && mqttClient.IsConnected)
                 {
                     return Break(SN, false, "已连接");
                 }
+
+                //工厂模式获取连接客户端对象
+                mqttClient = new MqttFactory().CreateMqttClient() as MQTTnet.Client.MqttClient;
+
+                //客户端支持 Connected、Disconnected 和 ApplicationMessageReceived 事件,
+                //用来处理客户端与服务端连接、客户端从服务端断开以及客户端收到消息的事情。
+
+                //消息(异步)
+                mqttClient.ApplicationMessageReceivedAsync += MqttClient_ApplicationMessageReceivedAsync;
+
+                //断开
+                mqttClient.DisconnectedAsync += MqttClient_DisconnectedAsync;
+
                 MqttClientOptionsBuilder mqttClientOptionsBuilder = new MqttClientOptionsBuilder();
                 //服务质量
                 mqttClientOptionsBuilder.WithWillQualityOfServiceLevel(mqttClientData.QualityOfServiceLevel);
@@ -330,13 +350,14 @@ namespace YSAI.Mqtt.client
             string SN = Depart("Off");
             try
             {
-                if (!mqttClient.IsConnected)
+                if (mqttClient == null || !mqttClient.IsConnected)
                 {
                     return Break(SN, false, "未连接");
                 }
                 //关闭与服务器的连接(异步)(等待执行完成)
                 mqttClient.DisconnectAsync().Wait();
                 mqttClient.Dispose();
+                mqttClient = null;
                 return Break(SN, true);
             }
             catch (Exception ex)
@@ -378,7 +399,7 @@ namespace YSAI.Mqtt.client
         public OperateResult GetStatus()
         {
             string SN = Depart("GetStatus");
-            if (!mqttClient.IsConnected)
+            if (mqttClient == null || !mqttClient.IsConnected)
             {
                 return Break(SN, false, "未连接", OutputLog: false);
             }

+ 1 - 1
src/YSAI.Mqtt/service/websocket/MqttWebSocketServiceData.cs

@@ -13,7 +13,7 @@ namespace YSAI.Mqtt.service.websocket
         /// <summary>
         /// MQTTwebsocket 接口
         /// </summary>
-        public interface IMqttWebSocketService : IOn, IEvent, IDisposable
+        public interface IMqttWebSocketService : IOn, IOff, IEvent, IDisposable
         { }
 
         /// <summary>

+ 55 - 15
src/YSAI.Mqtt/service/websocket/MqttWebSocketServiceOperate.cs

@@ -118,6 +118,9 @@ namespace YSAI.Mqtt.service.websocket
             return Task.Run(() => On());
         }
 
+
+        private CancellationTokenSource token;
+
         public OperateResult On()
         {
             //开始记录运行时间
@@ -132,27 +135,64 @@ namespace YSAI.Mqtt.service.websocket
                 {
                     OnEventHandler(this, new EventResult(true, $"[ {Steps.系统信息} ]MQTT WebSocket 服务端口被占用,清理占用此端口的进程失败"));
                 }
-                var host = Host.CreateDefaultBuilder(Array.Empty<string>()).ConfigureWebHostDefaults(
-                   webBuilder =>
-                   {
-                       webBuilder.UseKestrel(
-                           o =>
-                           {
-                               // MQTT 服务端口
-                               o.ListenAnyIP(mqttServiceData_Static.Port, l => l.UseMqtt());
-
-                               // MQTT WEBSOCKET 服务端口
-                               o.ListenAnyIP(mqttServiceData_Static.WsPort);
-                           });
-                       webBuilder.UseStartup<Startup>();
-                   }).RunConsoleAsync();
-                return Break(SN, true);
+                if (token == null)
+                {
+                    token = new CancellationTokenSource();
+                    Host.CreateDefaultBuilder(Array.Empty<string>()).ConfigureWebHostDefaults(webBuilder =>
+                    {
+                        webBuilder.UseKestrel(
+                                   o =>
+                                   {
+                                       // MQTT 服务端口
+                                       o.ListenAnyIP(mqttServiceData_Static.Port, l => l.UseMqtt());
+
+                                       // MQTT WEBSOCKET 服务端口
+                                       o.ListenAnyIP(mqttServiceData_Static.WsPort);
+                                   });
+                        webBuilder.UseStartup<Startup>();
+                    }).RunConsoleAsync(token.Token);
+
+                    return Break(SN, true);
+                }
+                else
+                {
+                    return Break(SN, false, "已连接");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public OperateResult Off()
+        {
+            //开始记录运行时间
+            string SN = Depart("Off");
+            try
+            {
+                if (token != null)
+                {
+                    token.Cancel();
+                    token = null;
+                    return Break(SN, true);
+                }
+                else
+                {
+                    return Break(SN, false, "未连接");
+                }
             }
             catch (Exception ex)
             {
                 return Break(SN, false, ex.Message, Exception: ex);
             }
         }
+
+        public Task<OperateResult> OffAsync()
+        {
+            return Task.Run(() => Off());
+        }
+
         /// <summary>
         /// 启动
         /// </summary>

+ 1 - 1
src/YSAI.Tool.Wpf/Main.xaml.cs

@@ -33,7 +33,7 @@ namespace YSAI.Tool.Wpf
                     if (navigationViews.Count > 0)
                     {
                         //第一次打开显示的界面
-                        navigationViews[0].Navigate(typeof(MqttClient));
+                        navigationViews[0].Navigate(typeof(MqttService));
                     }
                 });
             });

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

@@ -25,7 +25,7 @@
 		<PackageReference Include="YSAI.Mewtocol" Version="23.360.5691" />
 		<PackageReference Include="YSAI.Mitsubishi" Version="23.360.5691" />
 		<PackageReference Include="YSAI.Modbus" Version="23.360.5691" />
-		<PackageReference Include="YSAI.Mqtt" Version="23.360.22275" />
+		<PackageReference Include="YSAI.Mqtt" Version="23.360.26748" />
 		<PackageReference Include="YSAI.NetMQ" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Netty" Version="23.352.38022" />
 		<PackageReference Include="YSAI.Omron" Version="23.360.5691" />

+ 239 - 0
src/YSAI.Tool.Wpf/controllers/MqttServiceController.cs

@@ -0,0 +1,239 @@
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Mqtt.service;
+using YSAI.Unility;
+using static YSAI.Mqtt.service.MqttServiceData;
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class MqttServiceController : NotifyObject
+    {
+        public MqttServiceController()
+        {
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "Mqtt 服务端工具";
+            //配置文件名
+            FileName = typeof(MqttServiceData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Collapsed;
+            //Hex是否显示
+            HexVisibility = Visibility.Collapsed;
+            //信息格式;  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 RelayCommand(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (basics == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        private string _info = string.Empty;
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => _info;
+            set => SetProperty(ref _info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new RelayCommand<TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private Task Output(string Data, bool IsDate = true)
+        {
+            return Task.Run(() =>
+            {
+                System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                {
+                    if (Info?.Length > 10000)
+                    {
+                        Info = string.Empty;
+                    }
+                    if (IsDate)
+                    {
+                        Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                    }
+                    else
+                    {
+                        Info += $"{Data}\r\n";
+                    }
+                });
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new RelayCommand(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
+
+        #endregion 统一需要的数据
+
+        /// <summary>
+        /// 通信
+        /// </summary>
+        private MqttServiceOperate communication;
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public ICommand Start { get => new RelayCommand(OnStart); }
+        private void OnStart()
+        {
+            communication = MqttServiceOperate.Instance(BasicsData);
+            communication.OnEvent -= Communication_OnEvent;
+            communication.OnEvent += Communication_OnEvent;
+            OperateResult operateResult = communication.On();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+
+        /// <summary>
+        /// 停止
+        /// </summary>
+        public ICommand Stop { get => new RelayCommand(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message);
+        }
+    }
+}

+ 240 - 0
src/YSAI.Tool.Wpf/controllers/MqttWsServiceController.cs

@@ -0,0 +1,240 @@
+using CommunityToolkit.Mvvm.Input;
+using System.IO;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using YSAI.Core.Wpf.mvvm;
+using YSAI.Model.data;
+using YSAI.Mqtt.service.websocket;
+using YSAI.Unility;
+using static YSAI.Mqtt.service.websocket.MqttWebSocketServiceData;
+
+
+namespace YSAI.Tool.Wpf.controllers
+{
+    public class MqttWsServiceController : NotifyObject
+    {
+        public MqttWsServiceController()
+        {
+            //初始化基础数据
+            BasicsData = new Basics();
+            //工具标题
+            ToolTitle = "MqttWs 服务端工具";
+            //配置文件名
+            FileName = typeof(MqttWebSocketServiceData).Name;
+            //Ascii是否显示
+            AsciiVisibility = Visibility.Collapsed;
+            //Hex是否显示
+            HexVisibility = Visibility.Collapsed;
+            //信息格式;  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 RelayCommand(OnIncBasics); }
+
+        /// <summary>
+        /// 导入基础数据
+        /// </summary>
+        public void OnIncBasics()
+        {
+            (string RetFilePath, string RetFileName) Data = Unility.Windows.FileTool.SelectFiles("json");
+            if (!string.IsNullOrEmpty(Data.RetFilePath))
+            {
+                Basics? basics = FileTool.FileToString(Data.RetFilePath).ToJsonEntity<Basics>();
+                if (basics == null)
+                {
+                    Output("导入失败");
+                }
+                else
+                {
+                    Output("导入成功");
+                    BasicsData = basics;
+                }
+            }
+        }
+
+        /// <summary>
+        /// 导出基础数据命令
+        /// </summary>
+        public ICommand ExpBasics { get => new RelayCommand(OnExpBasics); }
+
+        /// <summary>
+        /// 导出基础数据
+        /// </summary>
+        public void OnExpBasics()
+        {
+            string path = Unility.Windows.FileTool.SelectFolder();
+            if (!string.IsNullOrEmpty(path))
+            {
+                FileTool.StringToFile(Path.Combine(path, $"{FileName}[{DateTime.Now.ToString("yyyyMMddHHmmss")}].json"), BasicsData.ToJson());
+                Output("导出成功");
+            }
+        }
+
+        private string _info = string.Empty;
+        /// <summary>
+        /// 信息
+        /// </summary>
+        public string Info
+        {
+            get => _info;
+            set => SetProperty(ref _info, value);
+        }
+
+        /// <summary>
+        /// 信息框事件
+        /// </summary>
+        public ICommand Info_TextChanged { get => new RelayCommand<TextChangedEventArgs>(OnInfo_TextChanged); }
+
+        /// <summary>
+        /// 信息框事件
+        /// 让滚动条一直处在最下方
+        /// </summary>
+        public void OnInfo_TextChanged(System.Windows.Controls.TextChangedEventArgs e)
+        {
+            System.Windows.Controls.TextBox textBox = (System.Windows.Controls.TextBox)e.Source;
+            textBox.SelectionStart = textBox.Text.Length;
+            textBox.SelectionLength = 0;
+            textBox.ScrollToEnd();
+        }
+
+        /// <summary>
+        /// 输出标准消息
+        /// </summary>
+        /// <param name="Data">数据</param>
+        /// <param name="IsDate">需要时间</param>
+        private Task Output(string Data, bool IsDate = true)
+        {
+            return Task.Run(() =>
+            {
+                System.Windows.Application.Current?.Dispatcher.Invoke(delegate ()
+                {
+                    if (Info?.Length > 10000)
+                    {
+                        Info = string.Empty;
+                    }
+                    if (IsDate)
+                    {
+                        Info += $" {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")} : {Data}\r\n";
+                    }
+                    else
+                    {
+                        Info += $"{Data}\r\n";
+                    }
+                });
+            });
+        }
+        /// <summary>
+        /// ascii
+        /// </summary>
+        public Visibility AsciiVisibility
+        {
+            get => GetProperty(() => AsciiVisibility);
+            set => SetProperty(() => AsciiVisibility, value);
+        }
+        /// <summary>
+        /// hex
+        /// </summary>
+        public Visibility HexVisibility
+        {
+            get => GetProperty(() => HexVisibility);
+            set => SetProperty(() => HexVisibility, value);
+        }
+
+        /// <summary>
+        /// 接收数据格式
+        /// 0 ASCII
+        /// 1 HEX
+        /// </summary>
+        public int InfoFormat
+        {
+            get => GetProperty(() => InfoFormat);
+            set => SetProperty(() => InfoFormat, value);
+        }
+
+        /// <summary>
+        /// 清空信息命令
+        /// </summary>
+        public ICommand Clear { get => new RelayCommand(OnClear); }
+
+        /// <summary>
+        /// 清空信息
+        /// </summary>
+        public void OnClear()
+        {
+            Info = string.Empty;
+        }
+
+        /// <summary>
+        /// 基础数据的显示隐藏
+        /// </summary>
+        public bool BasicsData_ToggleButtonIsChecked
+        {
+            get => GetProperty(() => BasicsData_ToggleButtonIsChecked);
+            set => SetProperty(() => BasicsData_ToggleButtonIsChecked, value);
+        }
+
+
+        #endregion 统一需要的数据
+
+        /// <summary>
+        /// 通信
+        /// </summary>
+        private MqttWebSocketServiceOperate communication;
+
+        /// <summary>
+        /// 启动
+        /// </summary>
+        public ICommand Start { get => new RelayCommand(OnStart); }
+        private void OnStart()
+        {
+            communication = MqttWebSocketServiceOperate.Instance(BasicsData);
+            communication.OnEvent -= Communication_OnEvent;
+            communication.OnEvent += Communication_OnEvent;
+            OperateResult operateResult = communication.On();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+
+        /// <summary>
+        /// 停止
+        /// </summary>
+        public ICommand Stop { get => new RelayCommand(OnStop); }
+        private void OnStop()
+        {
+            if (communication == null) return;
+            OperateResult operateResult = communication.Off();
+            Output(operateResult.ToJson().JsonFormatting());
+        }
+
+        private void Communication_OnEvent(object? sender, EventResult e)
+        {
+            Output(e.Message);
+        }
+    }
+}

+ 303 - 6
src/YSAI.Tool.Wpf/views/MqttService.xaml

@@ -3,10 +3,307 @@
              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"
-             mc:Ignorable="d" 
-             d:DesignHeight="450" d:DesignWidth="800">
-    <Grid>
-            
-    </Grid>
+             xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+             xmlns:txt="clr-namespace:YSAI.Core.Wpf.controls.textbox;assembly=YSAI.Core.Wpf"
+             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+             xmlns:pt="http://propertytools.org/wpf"
+             xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+             Background="{DynamicResource ContentBackgroundPicture}">
+    <UserControl.DataContext>
+        <c:MqttServiceController />
+    </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DatePicker.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeView.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="auto"/>
+                    </Grid.RowDefinitions>
+
+                    <!--导入导出-->
+                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
+                    </StackPanel>
+                    <!--属性表格-->
+                    <Grid Grid.Row="1" Panel.ZIndex="1">
+                        <Grid.Resources>
+                            <ResourceDictionary>
+                                <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="HorizontalAlignment" Value="Left"/>
+                                </Style>
+                                <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource DefaultComboBox}" >
+                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="Background" Value="White"/>
+                                    <Setter Property="VerticalAlignment" Value="Center"/>
+                                    <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
+                                </Style>
+                                <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" >
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <ToggleButton Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid  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 Start}"
+                                           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 Stop}"
+                                           Content="停止"/>
+                                </StackPanel>
+                            </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>

+ 303 - 5
src/YSAI.Tool.Wpf/views/MqttWsService.xaml

@@ -4,9 +4,307 @@
              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"
-             mc:Ignorable="d" 
-             d:DesignHeight="450" d:DesignWidth="800">
-    <Grid>
-            
-    </Grid>
+             xmlns:c="clr-namespace:YSAI.Tool.Wpf.controllers"
+             xmlns:txt="clr-namespace:YSAI.Core.Wpf.controls.textbox;assembly=YSAI.Core.Wpf"
+             xmlns:btn="clr-namespace:YSAI.Core.Wpf.controls.button;assembly=YSAI.Core.Wpf"
+             xmlns:pt="http://propertytools.org/wpf"
+             xmlns:helpers="clr-namespace:YSAI.Core.Wpf.style;assembly=YSAI.Core.Wpf"
+             xmlns:cs="clr-namespace:YSAI.Core.Wpf.converters;assembly=YSAI.Core.Wpf"
+             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:mvvm="clr-namespace:YSAI.Core.Wpf.mvvm;assembly=YSAI.Core.Wpf"
+             Background="{DynamicResource ContentBackgroundPicture}">
+    <UserControl.DataContext>
+        <c:MqttWsServiceController />
+    </UserControl.DataContext>
+
+
+
+    <!--资源加载-->
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <Style TargetType="ToolTip">
+                <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+            </Style>
+            <cs:CheckConverter x:Key="CheckConverter" />
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ComboBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Button.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DataGrid.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_Border.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TbaControl.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ScrollViewer.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_GroupBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TextBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_CheckBox.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_RadioButton.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_DatePicker.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_ContextMenu.xaml" />
+                <ResourceDictionary Source="pack://application:,,,/YSAI.Core.Wpf;component/resources/style/Style_TreeView.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+
+    <Border Background="#F0F2F0" Width="auto" Height="auto" CornerRadius="{DynamicResource WindowCornerRadius}" Margin="50">
+        <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0"  >
+            <GroupBox.Header>
+                <StackPanel Orientation="Horizontal">
+                    <Grid Background="Transparent">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+                        <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Tool}" Width="14" />
+                        <TextBlock Text="{Binding ToolTitle}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                    </Grid>
+                </StackPanel>
+            </GroupBox.Header>
+            <!--基础数据与功能区域-->
+            <Grid >
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="auto"/>
+                    <ColumnDefinition Width="*"/>
+                </Grid.ColumnDefinitions>
+                <!--基础数据-->
+                <Grid Grid.Column="0"  x:Name="propertyGrid" Margin="0,0,3,0" Width="550">
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="auto"/>
+                    </Grid.RowDefinitions>
+
+                    <!--导入导出-->
+                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,0,-30" Panel.ZIndex="2">
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding IncBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Inc}"
+                                          Content="导入"
+                                          BorderThickness="1,0,0,0" />
+                        <btn:ButtonControl  
+                                          Width="80"
+                                          Command="{Binding ExpBasics}" 
+                                          HorizontalAlignment="Center" 
+                                          VerticalAlignment="Center" 
+                                          IsMouseOverBorderBrushColor="{DynamicResource Control.Border.One.Color}"
+                                          BorderBrush="{DynamicResource Control.Border.Color}"
+                                          IsPressedBorderBrushColor="{DynamicResource Control.Border.Two.Color}"
+                                          Foreground="{DynamicResource Font.Content.Foreground}"
+                                          Icon="{DynamicResource Exp}"
+                                          Content="导出"
+                                          BorderThickness="1,0,0,0" />
+                    </StackPanel>
+                    <!--属性表格-->
+                    <Grid Grid.Row="1" Panel.ZIndex="1">
+                        <Grid.Resources>
+                            <ResourceDictionary>
+                                <Style TargetType="{x:Type Label}" >
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="HorizontalAlignment" Value="Left"/>
+                                </Style>
+                                <Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource DefaultComboBox}" >
+                                    <Setter Property="Height" Value="25"/>
+                                    <Setter Property="Background" Value="White"/>
+                                    <Setter Property="VerticalAlignment" Value="Center"/>
+                                    <Setter Property="helpers:Style_ComboBox.CornerRadius" Value="{DynamicResource WindowCornerRadius}"/>
+                                </Style>
+                                <Style TargetType="{x:Type pt:TextBoxEx}" BasedOn="{StaticResource TextBoxStyle2}">
+                                    <Setter Property="FontSize" Value="13"/>
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                    <Setter Property="BorderBrush" Value="{DynamicResource Control.Border.Color}"/>
+                                    <Setter Property="HorizontalContentAlignment" Value="Center"/>
+                                    <Setter Property="VerticalContentAlignment" Value="Center"/>
+                                </Style>
+
+                                <Style TargetType="CheckBox" BasedOn="{StaticResource CheckBoxStyle}"/>
+
+                                <Style TargetType="ContentControl" >
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="Expander">
+                                    <Setter Property="Foreground" Value="{DynamicResource Font.Content.Foreground}"/>
+                                </Style>
+
+                                <Style TargetType="RadioButton" BasedOn="{StaticResource RadioButtonStyle}"/>
+
+
+                                <Style TargetType="GroupBox" BasedOn="{StaticResource GroupBoxTab}"/>
+
+
+                                <DataTemplate x:Key="HeaderTemplate">
+                                    <StackPanel Orientation="Horizontal">
+                                        <Grid>
+                                            <Grid.ColumnDefinitions>
+                                                <ColumnDefinition Width="auto" />
+                                                <ColumnDefinition Width="*" />
+                                            </Grid.ColumnDefinitions>
+                                            <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource ConfigBase}" Width="14" />
+                                            <TextBlock Text="{Binding}" FontSize="13"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                        </Grid>
+                                    </StackPanel>
+                                </DataTemplate>
+
+                            </ResourceDictionary>
+                        </Grid.Resources>
+                        <pt:PropertyGrid  Margin="1,-4,1,0"
+SelectedObject="{Binding BasicsData}"
+TabVisibility="VisibleIfMoreThanOne" 
+TextBlock.Foreground="{DynamicResource Font.Content.Foreground}" 
+Foreground="{DynamicResource Font.Content.Foreground}"
+BorderBrush="{DynamicResource Control.Border.Color}"
+CategoryHeaderTemplate="{StaticResource HeaderTemplate}"/>
+                    </Grid>
+                </Grid>
+
+                <!--功能模块与信息-->
+                <Grid Grid.Column="1" >
+                    <Grid.RowDefinitions>
+                        <RowDefinition Height="auto"/>
+                        <RowDefinition Height="*"/>
+                    </Grid.RowDefinitions>
+                    <ToggleButton Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="8,8,0,0" ToolTip="基础数据[隐藏/显示]" Panel.ZIndex="3" IsChecked="{Binding BasicsData_ToggleButtonIsChecked}">
+                        <ToggleButton.Template>
+                            <ControlTemplate TargetType="{x:Type ToggleButton}">
+                                <Image x:Name="image" Source="{DynamicResource GoLeft_Two}" Stretch="Fill" Width="15" Height="15" />
+                                <ControlTemplate.Triggers>
+                                    <Trigger Property="IsChecked" Value="True">
+                                        <Setter Property="Source" TargetName="image" Value="{DynamicResource GoRight_Two}"/>
+                                    </Trigger>
+                                </ControlTemplate.Triggers>
+                            </ControlTemplate>
+                        </ToggleButton.Template>
+                        <ToggleButton.Triggers>
+                            <EventTrigger RoutedEvent="ToggleButton.Unchecked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="0" To="550" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0,0,3,0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                            <EventTrigger RoutedEvent="ToggleButton.Checked">
+                                <BeginStoryboard>
+                                    <Storyboard>
+                                        <DoubleAnimation Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Width" From="550" To="0" Duration="0:0:0.7"/>
+                                        <ThicknessAnimationUsingKeyFrames Storyboard.TargetName="propertyGrid" Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
+                                            <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0,0,3,0" />
+                                            <SplineThicknessKeyFrame KeyTime="00:00:0.7" Value="0" />
+                                        </ThicknessAnimationUsingKeyFrames>
+                                    </Storyboard>
+                                </BeginStoryboard>
+                            </EventTrigger>
+                        </ToggleButton.Triggers>
+                    </ToggleButton>
+                    <!--功能模块-->
+                    <GroupBox Style="{StaticResource GroupBoxTab}" Margin="0" Grid.Row="0">
+                        <GroupBox.Header>
+                            <StackPanel Orientation="Horizontal">
+                                <Grid Background="transparent">
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="auto" />
+                                        <ColumnDefinition Width="*" />
+                                    </Grid.ColumnDefinitions>
+                                    <Image Grid.Column="0" Margin="10,0,8,0" Source="{DynamicResource Function}" Width="14" />
+                                    <TextBlock Text="功能" FontSize="13" Margin="0,0,10,0"  Grid.Column="1" Foreground="{DynamicResource Font.Content.Foreground}" />
+                                </Grid>
+                            </StackPanel>
+                        </GroupBox.Header>
+                        <!--■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-->
+
+
+
+
+
+
+
+
+                        <Grid>
+                            <Grid.RowDefinitions>
+                                <RowDefinition Height="auto"/>
+                                <RowDefinition Height="*"/>
+                            </Grid.RowDefinitions>
+                            <!--Start / Stop-->
+                            <Grid  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 Start}"
+                                           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 Stop}"
+                                           Content="停止"/>
+                                </StackPanel>
+                            </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>

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

@@ -34,7 +34,7 @@ List<string> strings = new List<string>
     //"YSAI.Redis",
 
     //"YSAI.Kafka",
-    //"YSAI.Mqtt",
+    "YSAI.Mqtt",
     //"YSAI.NetMQ",
     //"YSAI.Netty",
     //"YSAI.RabbitMQ",