Просмотр исходного кода

1. kafka 处理任务优化
2. 版本更新

Shun 2 лет назад
Родитель
Сommit
3225555260

+ 6 - 2
README.md

@@ -522,6 +522,10 @@ while(true)
 4. 修改PACK生成代码位置,与主代码不存在引用关系
 
 #### 2023-12-5
-1. 传输协议 netty 更新 
+1. 传输协议 netty 更新 ,修复服务端无法群发问题
 2. 修改三菱采集协议包问题
-3. tool 存在遗留问题待解决
+3. tool 存在遗留问题待解决
+
+#### 2023-12-7
+1. kafka 处理任务优化
+2. 版本更新

+ 3 - 3
src/YSAI.Controls/tabcontrol/TabControl.xaml.cs

@@ -555,10 +555,10 @@ namespace YSAI.Controls.tabcontrol
             {
                 if (tabItem != null)
                 {
-                    var header = Helper.CloneElement(tabItem.Header);
-                    var icon = tabItem.Icon == null ? null : Helper.CloneElement(tabItem.Icon);
+                    //var header = Helper.CloneElement(tabItem.Header);
+                    var icon = tabItem.Icon == null ? null : tabItem.Icon;
 
-                    var mi = new MenuItem { Header = header, Icon = icon, Tag = index++.ToString() };
+                    var mi = new MenuItem { Header = tabItem.Header, Icon = icon, Tag = index++.ToString() };
                     mi.Click += ContextMenuItem_Click;
 
                     _toggleButton.ContextMenu.Items.Add(mi);

+ 1 - 1
src/YSAI.Controls/tabcontrol/TabItem.cs

@@ -67,7 +67,7 @@ namespace YSAI.Controls.tabcontrol
         {
             base.OnMouseEnter(e);
 
-            this.ToolTip = Helper.CloneElement(Header);
+            this.ToolTip = Header;
             e.Handled = true;
         }
 

+ 1 - 8
src/YSAI.DAQ.sln

@@ -81,8 +81,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Redis", "YSAI.Redis\YS
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Model", "YSAI.Model\YSAI.Model.csproj", "{2E999BFE-9128-4BAD-9BB5-88C20295BE61}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Rest", "YSAI.Rest\YSAI.Rest.csproj", "{6A818E8C-144C-46E7-8C66-B66CD85487C0}"
-EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{2E080205-D55D-43C9-BD56-A0FDC62A790C}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.DAQ.Samples", "YSAI.DAQ.Samples\YSAI.DAQ.Samples.csproj", "{5BC237BD-BA54-4846-AA53-6067C0786CFF}"
@@ -101,7 +99,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Tests", "YSAI.Tests\YS
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Redis.Samples", "YSAI.Redis.Samples\YSAI.Redis.Samples.csproj", "{6B0643C4-FFE3-4B32-80D9-9E0E40EB2907}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YSAI.Ver.Manage.Tool", "YSAI.Ver.Manage.Tool\YSAI.Ver.Manage.Tool.csproj", "{41E1A114-05D0-4046-81AF-82DC74CA52ED}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Ver.Manage.Tool", "YSAI.Ver.Manage.Tool\YSAI.Ver.Manage.Tool.csproj", "{41E1A114-05D0-4046-81AF-82DC74CA52ED}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -233,10 +231,6 @@ Global
 		{2E999BFE-9128-4BAD-9BB5-88C20295BE61}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{2E999BFE-9128-4BAD-9BB5-88C20295BE61}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{2E999BFE-9128-4BAD-9BB5-88C20295BE61}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6A818E8C-144C-46E7-8C66-B66CD85487C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6A818E8C-144C-46E7-8C66-B66CD85487C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6A818E8C-144C-46E7-8C66-B66CD85487C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6A818E8C-144C-46E7-8C66-B66CD85487C0}.Release|Any CPU.Build.0 = Release|Any CPU
 		{5BC237BD-BA54-4846-AA53-6067C0786CFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{5BC237BD-BA54-4846-AA53-6067C0786CFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{5BC237BD-BA54-4846-AA53-6067C0786CFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -313,7 +307,6 @@ Global
 		{87606DDA-82DA-4BCD-87B3-E7CEFB05EADC} = {F23C3553-3FE7-4ECC-9BBA-8C498C3B4398}
 		{F917D5C2-A067-47F3-8E18-1CD2C95FEC29} = {F23C3553-3FE7-4ECC-9BBA-8C498C3B4398}
 		{2E999BFE-9128-4BAD-9BB5-88C20295BE61} = {D60224CF-7F12-453B-851E-B5C01F9D2BBE}
-		{6A818E8C-144C-46E7-8C66-B66CD85487C0} = {9D8EDBBA-7A97-4D84-9B12-7FCC2F834046}
 		{5BC237BD-BA54-4846-AA53-6067C0786CFF} = {2E080205-D55D-43C9-BD56-A0FDC62A790C}
 		{50835493-724D-478C-B497-3100AD1F1362} = {2E080205-D55D-43C9-BD56-A0FDC62A790C}
 		{2150F1EF-794B-48CD-A847-DB0061197741} = {2E080205-D55D-43C9-BD56-A0FDC62A790C}

+ 10 - 10
src/YSAI.Kafka/KafkaOperate.cs

@@ -99,9 +99,9 @@ namespace YSAI.Kafka
         private bool IsOpen { get; set; }
 
         /// <summary>
-        /// 轮询状态
+        /// 订阅令牌
         /// </summary>
-        private bool PollingState = false;
+        private CancellationTokenSource tokenSource;
 
         /// <summary>
         /// 释放
@@ -118,13 +118,13 @@ namespace YSAI.Kafka
         /// 轮询消费
         /// </summary>
         /// <returns></returns>
-        private Task Polling()
+        private Task Polling(CancellationTokenSource source)
         {
             return Task.Run(() =>
             {
                 try
                 {
-                    while (PollingState)
+                    while (!source.IsCancellationRequested)
                     {
                         ConsumeResult<string, string>? result = Consumer?.Consume();
                         if (result != null)
@@ -150,7 +150,7 @@ namespace YSAI.Kafka
                 {
                     OnEventHandler(this, new EventResult(false, $"轮询消费异常:{ex.Message}"));
                 }
-            });
+            }, source.Token);
         }
 
         /// <summary>
@@ -311,13 +311,12 @@ namespace YSAI.Kafka
                         Consumer.Subscribe(TopicArray);
 
                         //当订阅状态为false 调用轮询函数
-                        if (!PollingState)
+                        if (tokenSource == null)
                         {
-                            //设置轮询状态
-                            PollingState = true;
+                            tokenSource = new CancellationTokenSource();
 
                             //异步轮询
-                            Polling();
+                            Polling(tokenSource);
                         }
 
                         return Break(SN, true);
@@ -468,7 +467,8 @@ namespace YSAI.Kafka
                         {
                             //小于或等于零,直接关闭订阅
                             //设置轮询状态
-                            PollingState = false;
+                            tokenSource.Cancel();
+                            tokenSource = null;
                             //先关订阅
                             Consumer.Unsubscribe();
                             //关闭

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

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

+ 10 - 40
src/YSAI.Mvvm/NotifyObject.cs

@@ -15,13 +15,12 @@ namespace YSAI.Mvvm
         {
             return GetPropertyNameFast(expression);
         }
-
         internal static string GetPropertyNameFast(LambdaExpression expression)
         {
             MemberExpression memberExpression = expression.Body as MemberExpression;
             if (memberExpression == null)
             {
-                throw new ArgumentException("MemberExpression is expected in expression.Body", "expression");
+                throw new ArgumentException("MemberExpression is expected in expression.Body", "NotifyObject");
             }
             const string vblocalPrefix = "$VB$Local_";
             var member = memberExpression.Member;
@@ -34,35 +33,29 @@ namespace YSAI.Mvvm
         }
 
         public event PropertyChangedEventHandler PropertyChanged;
-
         protected bool SetProperty<T>(ref T storage, T value, Expression<Func<T>> expression, Action changedCallback)
         {
             return SetProperty(ref storage, value, GetPropertyName(expression), changedCallback);
         }
-
         protected bool SetProperty<T>(ref T storage, T value, Expression<Func<T>> expression)
         {
             return SetProperty<T>(ref storage, value, expression, null);
         }
-
         protected void RaisePropertyChanged<T>(Expression<Func<T>> expression)
         {
             RaisePropertyChanged(GetPropertyName(expression));
         }
-
         protected void RaisePropertiesChanged<T1, T2>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2)
         {
             RaisePropertyChanged(expression1);
             RaisePropertyChanged(expression2);
         }
-
         protected void RaisePropertiesChanged<T1, T2, T3>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3)
         {
             RaisePropertyChanged(expression1);
             RaisePropertyChanged(expression2);
             RaisePropertyChanged(expression3);
         }
-
         protected void RaisePropertiesChanged<T1, T2, T3, T4>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3, Expression<Func<T4>> expression4)
         {
             RaisePropertyChanged(expression1);
@@ -70,7 +63,6 @@ namespace YSAI.Mvvm
             RaisePropertyChanged(expression3);
             RaisePropertyChanged(expression4);
         }
-
         protected void RaisePropertiesChanged<T1, T2, T3, T4, T5>(Expression<Func<T1>> expression1, Expression<Func<T2>> expression2, Expression<Func<T3>> expression3, Expression<Func<T4>> expression4, Expression<Func<T5>> expression5)
         {
             RaisePropertyChanged(expression1);
@@ -79,29 +71,24 @@ namespace YSAI.Mvvm
             RaisePropertyChanged(expression4);
             RaisePropertyChanged(expression5);
         }
-
         protected T GetProperty<T>(Expression<Func<T>> expression)
         {
             return GetPropertyCore<T>(GetPropertyName(expression));
         }
-
         protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action<T> changedCallback)
         {
             string propertyName = GetPropertyName(expression);
             return SetPropertyCore(propertyName, value, changedCallback);
         }
-
         protected bool SetProperty<T>(Expression<Func<T>> expression, T value)
         {
             return SetProperty(expression, value, (Action)null);
         }
-
         protected bool SetProperty<T>(Expression<Func<T>> expression, T value, Action changedCallback)
         {
             string propertyName = GetPropertyName(expression);
             return SetPropertyCore(propertyName, value, changedCallback);
         }
-
         protected virtual bool SetProperty<T>(ref T storage, T value, string propertyName, Action changedCallback)
         {
             VerifyAccess();
@@ -112,62 +99,51 @@ namespace YSAI.Mvvm
             changedCallback?.Invoke();
             return true;
         }
-
         protected bool SetProperty<T>(ref T storage, T value, string propertyName)
         {
             return this.SetProperty<T>(ref storage, value, propertyName, null);
         }
-
         protected T GetValue<T>([CallerMemberName] string propertyName = null)
         {
             GuardPropertyName(propertyName);
             return GetPropertyCore<T>(propertyName);
         }
-
         protected bool SetValue<T>(T value, [CallerMemberName] string propertyName = null)
         {
             return SetValue(value, default(Action), propertyName);
         }
-
         protected bool SetValue<T>(T value, Action changedCallback, [CallerMemberName] string propertyName = null)
         {
             return SetPropertyCore(propertyName, value, changedCallback);
         }
-
         protected bool SetValue<T>(T value, Action<T> changedCallback, [CallerMemberName] string propertyName = null)
         {
             return SetPropertyCore(propertyName, value, changedCallback);
         }
-
         protected bool SetValue<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
         {
             return SetValue(ref storage, value, default(Action), propertyName);
         }
-
         protected bool SetValue<T>(ref T storage, T value, Action changedCallback, [CallerMemberName] string propertyName = null)
         {
             GuardPropertyName(propertyName);
             return SetProperty(ref storage, value, propertyName, changedCallback);
         }
-
-        private static void GuardPropertyName(string propertyName)
+        static void GuardPropertyName(string propertyName)
         {
             if (string.IsNullOrEmpty(propertyName))
                 throw new ArgumentNullException(nameof(propertyName));
         }
 
         #region RaisePropertyChanged
-
         protected void RaisePropertyChanged(string propertyName)
         {
             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
         }
-
         protected void RaisePropertyChanged()
         {
             RaisePropertiesChanged(null);
         }
-
         protected void RaisePropertiesChanged(params string[] propertyNames)
         {
             if (propertyNames == null || propertyNames.Length == 0)
@@ -180,18 +156,15 @@ namespace YSAI.Mvvm
                 RaisePropertyChanged(propertyName);
             }
         }
-
-        #endregion RaisePropertyChanged
+        #endregion
 
         #region property bag
-
-        private Dictionary<string, object> _propertyBag;
-        private Dictionary<string, object> PropertyBag => _propertyBag ?? (_propertyBag = new Dictionary<string, object>());
+        Dictionary<string, object> _propertyBag;
+        Dictionary<string, object> PropertyBag => _propertyBag ?? (_propertyBag = new Dictionary<string, object>());
 #if DEBUG
         internal Dictionary<string, object> PropertyBagForTests => PropertyBag;
 #endif
-
-        private T GetPropertyCore<T>(string propertyName)
+        T GetPropertyCore<T>(string propertyName)
         {
             object val;
             if (PropertyBag.TryGetValue(propertyName, out val))
@@ -199,7 +172,7 @@ namespace YSAI.Mvvm
             return default(T);
         }
 
-        private bool SetPropertyCore<T>(string propertyName, T value, Action changedCallback)
+        bool SetPropertyCore<T>(string propertyName, T value, Action changedCallback)
         {
             T oldValue;
             var res = SetPropertyCore(propertyName, value, out oldValue);
@@ -209,8 +182,7 @@ namespace YSAI.Mvvm
             }
             return res;
         }
-
-        private bool SetPropertyCore<T>(string propertyName, T value, Action<T> changedCallback)
+        bool SetPropertyCore<T>(string propertyName, T value, Action<T> changedCallback)
         {
             T oldValue;
             var res = SetPropertyCore(propertyName, value, out oldValue);
@@ -220,7 +192,6 @@ namespace YSAI.Mvvm
             }
             return res;
         }
-
         protected virtual bool SetPropertyCore<T>(string propertyName, T value, out T oldValue)
         {
             VerifyAccess();
@@ -242,11 +213,10 @@ namespace YSAI.Mvvm
         {
         }
 
-        private static bool CompareValues<T>(T storage, T value)
+        static bool CompareValues<T>(T storage, T value)
         {
             return EqualityComparer<T>.Default.Equals(storage, value);
         }
-
-        #endregion property bag
+        #endregion
     }
 }

+ 0 - 16
src/YSAI.Rest/RestData.cs

@@ -1,16 +0,0 @@
-namespace YSAI.Rest
-{
-    public class RestData
-    {
-        /// <summary>
-        /// 基础数据
-        /// </summary>
-        public class Basics
-        {
-            /// <summary>
-            /// 地址
-            /// </summary>
-            public string Uri { get; set; }
-        }
-    }
-}

+ 0 - 94
src/YSAI.Rest/RestOperate.cs

@@ -1,94 +0,0 @@
-using YSAI.Model.data;
-using YSAI.Model.@interface;
-
-namespace YSAI.Rest
-{
-
-    public class RestOperate : IBaseAbstract, IRelay
-    {
-        public OperateResult CreateInstance<T>(T Basics)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> CreateInstanceAsync<T>(T Basics)
-        {
-            throw new NotImplementedException();
-        }
-
-        public void Dispose()
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult GetParam()
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> GetParamAsync()
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult GetStatus()
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> GetStatusAsync()
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult Off()
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> OffAsync()
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult On()
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> OnAsync()
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult Produce(string Topic, string Content)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> ProduceAsync(string Topic, string Content)
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult Subscribe(string Topic)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> SubscribeAsync(string Topic)
-        {
-            throw new NotImplementedException();
-        }
-
-        public OperateResult UnSubscribe(string Topic)
-        {
-            throw new NotImplementedException();
-        }
-
-        public Task<OperateResult> UnSubscribeAsync(string Topic)
-        {
-            throw new NotImplementedException();
-        }
-    }
-}

+ 0 - 22
src/YSAI.Rest/YSAI.Rest.csproj

@@ -1,22 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-  <PropertyGroup>
-    <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
-    <Version>23.333.11249</Version>
-    <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
-    <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
-    <Authors>Shun</Authors>
-    <Company>YSAI</Company>
-    <Product>SCADA</Product>
-    <GenerateDocumentationFile>True</GenerateDocumentationFile>
-    <DescriptionType>扩展工具</DescriptionType>
-    <DescriptionName>Rest</DescriptionName>
-    <DescriptionDetails>Client [ Publish、Subscribe ]、Service</DescriptionDetails>
-    <Description>$(DescriptionType):$(DescriptionName) ( $(DescriptionDetails) )</Description>
-  </PropertyGroup>
-  <ItemGroup>
-    <PackageReference Include="RabbitMQ.Client" Version="6.7.0" />
-    <PackageReference Include="YSAI.Model" Version="23.338.16757" />
-  </ItemGroup>
-</Project>

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

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

+ 87 - 48
src/YSAI.Tool/MainWindow.xaml

@@ -39,60 +39,99 @@
             </hm:HamburgerMenu>
         </Border>
         <Grid Grid.Column="1">
-            <tc:TabControl TabStripPlacement="Top" 
-                           VerticalContentAlignment="Center"  
-                           Background="Transparent" 
-                           ItemsSource="{Binding TabControlItemsSource}" 
-                           AllowDelete="True"
-                           AllowAddNew="False"
-                           SelectNewTabOnCreate="False"
-                           AddNewTabToEnd="False">
-
-                <tc:TabControl.TabItemNormalBackground>
-                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
-                        <GradientStop Color="#FFFCFDFD" Offset="0"/>
-                        <GradientStop Color="#FFE5EAF5" Offset="0.3"/>
-                        <GradientStop Color="#FFCFD7EB" Offset="0.3"/>
-                        <GradientStop Color="#FFE0E5F5" Offset="0.7"/>
-                        <GradientStop Color="#FFECEEFC" Offset="1"/>
-                    </LinearGradientBrush>
-                </tc:TabControl.TabItemNormalBackground>
-
-                <tc:TabControl.TabItemSelectedBackground>
-                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
-                        <GradientStop Color="#FFFBFDFE" Offset="0"/>
-                        <GradientStop Color="#FFEAF6FB" Offset="0.3"/>
-                        <GradientStop Color="#FFCEE7FA" Offset="0.3"/>
-                        <GradientStop Color="#FFB9D1FA" Offset="1"/>
-                    </LinearGradientBrush>
-                </tc:TabControl.TabItemSelectedBackground>
+            <TabControl ItemsSource="{Binding TabControlItemsSource}"  TabStripPlacement="Top" VerticalContentAlignment="Center" SelectedItem="{Binding TabControlSelectedItem}" Background="Transparent" BorderBrush="Transparent">
+                <TabControl.ItemTemplate>
+                    <DataTemplate>
+                        <Grid Background="Transparent">
+                            <Grid.ColumnDefinitions>
+                                <ColumnDefinition/>
+                                <ColumnDefinition/>
+                                <ColumnDefinition/>
+                            </Grid.ColumnDefinitions>
+                            <Image Grid.Column="0" Source="{Binding Icon}" Height="16" Width="16" Margin="2,0,2,0" VerticalAlignment="Center"/>
+                            <TextBlock Grid.Column="1" Text="{Binding Title}" />
+                            <Button Grid.Column="2" Name="PART_CloseButton"  Height="auto" Width="20" WindowChrome.IsHitTestVisibleInChrome="True">
+                                <!--关闭按钮的模版-->
+                                <Button.Template>
+                                    <ControlTemplate  TargetType="{x:Type Button}">
+                                        <Border TextBlock.Foreground="{TemplateBinding Foreground}" x:Name="Border">
+                                            <Border.BorderBrush>
+                                                <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
+                                                    <LinearGradientBrush.GradientStops>
+                                                        <GradientStopCollection>
+                                                            <GradientStop Color="{DynamicResource BorderLightColor}" Offset="0.0" />
+                                                            <GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1.0" />
+                                                        </GradientStopCollection>
+                                                    </LinearGradientBrush.GradientStops>
+                                                </LinearGradientBrush>
+                                            </Border.BorderBrush>
+                                            <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True" />
+                                        </Border>
+                                        <ControlTemplate.Triggers>
+                                            <Trigger Property="IsDefault" Value="true">
+                                                <Setter TargetName="Border" Property="BorderBrush">
+                                                    <Setter.Value>
+                                                        <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
+                                                            <GradientBrush.GradientStops>
+                                                                <GradientStopCollection>
+                                                                    <GradientStop Color="{DynamicResource DefaultBorderBrushLightBrush}" Offset="0.0" />
+                                                                    <GradientStop Color="{DynamicResource DefaultBorderBrushDarkColor}" Offset="1.0" />
+                                                                </GradientStopCollection>
+                                                            </GradientBrush.GradientStops>
+                                                        </LinearGradientBrush>
+                                                    </Setter.Value>
+                                                </Setter>
+                                            </Trigger>
 
-                <tc:TabControl.TabItemMouseOverBackground>
-                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
-                        <GradientStop Color="#FFFCFDFD" Offset="0"/>
-                        <GradientStop Color="#FFC6DDF7" Offset="0.3"/>
-                        <GradientStop Color="#FF99C6EE" Offset="0.3"/>
-                        <GradientStop Color="#FFB6D6F1" Offset="0.7"/>
-                        <GradientStop Color="#FFD9E9F9" Offset="1"/>
-                    </LinearGradientBrush>
-                </tc:TabControl.TabItemMouseOverBackground>
+                                            <!--没有被按下,并且鼠标还在上方-->
+                                            <MultiTrigger>
+                                                <MultiTrigger.Conditions>
+                                                    <!--被按下-->
+                                                    <Condition Property="IsPressed" Value="False" />
+                                                    <!--鼠标在上方-->
+                                                    <Condition Property="IsMouseOver" Value="True" />
+                                                </MultiTrigger.Conditions>
+                                                <Setter Property="Opacity" TargetName="Border" Value="0.8" />
+                                                <Setter Property="Background" TargetName="Border" Value="{DynamicResource CloseCaptionButtonBackgroundBrush}" />
+                                            </MultiTrigger>
 
+                                            <!--被按下,并且鼠标还在上方-->
+                                            <MultiTrigger>
+                                                <MultiTrigger.Conditions>
+                                                    <!--被按下-->
+                                                    <Condition Property="IsPressed" Value="True" />
+                                                    <!--鼠标在上方-->
+                                                    <Condition Property="IsMouseOver" Value="True" />
+                                                </MultiTrigger.Conditions>
+                                                <Setter Property="Background" TargetName="Border" Value="{DynamicResource CloseCaptionButtonPressedBackgroundBrush}" />
+                                            </MultiTrigger>
 
-                <!--通过使用ItemTemplate属性绑定到MyObject实例的Header属性来设置TabItem Header-->
-                <tc:TabControl.ItemTemplate>
-                    <DataTemplate>
-                        <TextBlock Text="{Binding Title}" />
+                                            <!--没有被按下,鼠标也不在上方-->
+                                            <MultiTrigger>
+                                                <MultiTrigger.Conditions>
+                                                    <!--被按下-->
+                                                    <Condition Property="IsPressed" Value="False" />
+                                                    <!--鼠标在上方-->
+                                                    <Condition Property="IsMouseOver" Value="False" />
+                                                </MultiTrigger.Conditions>
+                                                <Setter Property="Background" TargetName="Border" Value="Transparent" />
+                                            </MultiTrigger>
+                                        </ControlTemplate.Triggers>
+                                    </ControlTemplate>
+                                </Button.Template>
+                                <StackPanel Orientation="Horizontal">
+                                    <Image Source="{DynamicResource CloseBase}" Width="{DynamicResource CloseImageWidth}" Stretch="Uniform" />
+                                </StackPanel>
+                            </Button>
+                        </Grid>
                     </DataTemplate>
-                </tc:TabControl.ItemTemplate>
-
-                <!-- TabObject类型的DataTemplate, TabItems的内容-->
-                <tc:TabControl.ContentTemplate>
-                    <DataTemplate >
+                </TabControl.ItemTemplate>
+                <TabControl.ContentTemplate>
+                    <DataTemplate>
                         <ContentControl Content="{Binding UserControl}" />
                     </DataTemplate>
-                </tc:TabControl.ContentTemplate>
-                
-            </tc:TabControl>
+                </TabControl.ContentTemplate>
+            </TabControl>
         </Grid>
     </Grid>
 </base:WindowBase>

+ 140 - 93
src/YSAI.Tool/MainWindowController.cs

@@ -2,6 +2,7 @@
 using System.Collections.ObjectModel;
 using System.Windows.Controls;
 using System.Windows.Input;
+using System.Windows.Media;
 using YSAI.Langs;
 using YSAI.Mvvm;
 using YSAI.Tool.Core.aboutUs;
@@ -28,11 +29,11 @@ namespace YSAI.Tool
         /// <summary>
         /// 图标
         /// </summary>
-        //public ImageSource Icon
-        //{
-        //    get => GetProperty(() => Icon);
-        //    set => SetProperty(() => Icon, value);
-        //}
+        public ImageSource Icon
+        {
+            get => GetProperty(() => Icon);
+            set => SetProperty(() => Icon, value);
+        }
         /// <summary>
         /// 标题
         /// </summary>
@@ -60,11 +61,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "AboutUsTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand CanTool
@@ -72,11 +71,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "CanTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand MqttClientTool
@@ -84,11 +81,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "MqttClientTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand MqttServiceTool
@@ -96,11 +91,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "MqttServiceTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand MqttWebSocketServiceTool
@@ -108,11 +101,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "MqttWebSocketServiceTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand OpcDaHttpClientTool
@@ -120,11 +111,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "OpcDaHttpClientTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand OpcUaClientTool
@@ -132,11 +121,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "OpcUaClientTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand OpcUaServiceTool
@@ -144,11 +131,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "OpcUaServiceTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand SerialPortTool
@@ -156,11 +141,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "SerialPortTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand SocketTcpClientTool
@@ -168,11 +151,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "SocketTcpClientTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand SocketTcpServerTool
@@ -180,11 +161,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "SocketTcpServerTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand SocketUdpTool
@@ -192,11 +171,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "SocketUdpTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         public ICommand SvgTool
@@ -204,11 +181,9 @@ namespace YSAI.Tool
             get => new CommandX(() =>
             {
                 string name = "SvgTool";
-                TabControlItemsSource.Add(new Source
-                {
-                    Title = name,
-                    UserControl = UserControls[name]
-                });
+                Source source = Sources[name];
+                if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+                TabControlSelectedItem = source;
             });
         }
         #endregion 控件
@@ -217,41 +192,105 @@ namespace YSAI.Tool
         {
             //设置初始语言
             LangsHelper.SetLangs(LangsHelper.GetLangs());
-            //添加控件集合
-            UserControls.AddOrUpdate("CanTool", new CanTool(), (k, v) => new CanTool());
-            UserControls.AddOrUpdate("MqttClientTool", new MqttClientTool(), (k, v) => new MqttClientTool());
-            UserControls.AddOrUpdate("MqttServiceTool", new MqttServiceTool(), (k, v) => new MqttServiceTool());
-            UserControls.AddOrUpdate("MqttWebSocketServiceTool", new MqttWebSocketServiceTool(), (k, v) => new MqttWebSocketServiceTool());
-            UserControls.AddOrUpdate("OpcDaHttpClientTool", new OpcDaHttpClientTool(), (k, v) => new OpcDaHttpClientTool());
-            UserControls.AddOrUpdate("OpcUaClientTool", new OpcUaClientTool(), (k, v) => new OpcUaClientTool());
-            UserControls.AddOrUpdate("OpcUaServiceTool", new OpcUaServiceTool(), (k, v) => new OpcUaServiceTool());
-            UserControls.AddOrUpdate("SerialPortTool", new SerialPortTool(), (k, v) => new SerialPortTool());
-            UserControls.AddOrUpdate("SocketTcpClientTool", new SocketTcpClientTool(), (k, v) => new SocketTcpClientTool());
-            UserControls.AddOrUpdate("SocketTcpServerTool", new SocketTcpServerTool(), (k, v) => new SocketTcpServerTool());
-            UserControls.AddOrUpdate("SocketUdpTool", new SocketUdpTool(), (k, v) => new SocketUdpTool());
-            UserControls.AddOrUpdate("SvgTool", new SvgTool(), (k, v) => new SvgTool());
-            UserControls.AddOrUpdate("AboutUsTool", new AboutUsTool(), (k, v) => new AboutUsTool());
 
             if (TabControlItemsSource == null)
             {
                 TabControlItemsSource = new ObservableCollection<Source>();
             }
 
-            TabControlItemsSource.Add(new Source
-            {
-                Title = "AboutUsTool",
-                UserControl = UserControls["AboutUsTool"]
-            });
-        }
 
+            string name = "CanTool";
+            UserControl control = new CanTool();
+            Source source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "MqttClientTool";
+            control = new MqttClientTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "MqttServiceTool";
+            control = new MqttServiceTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "MqttWebSocketServiceTool";
+            control = new MqttWebSocketServiceTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "OpcDaHttpClientTool";
+            control = new OpcDaHttpClientTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "OpcUaClientTool";
+            control = new OpcUaClientTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "OpcUaServiceTool";
+            control = new OpcUaServiceTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "SerialPortTool";
+            control = new SerialPortTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "SocketTcpClientTool";
+            control = new SocketTcpClientTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            name = "SocketTcpServerTool";
+            control = new SocketTcpServerTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
 
+            name = "SocketUdpTool";
+            control = new SocketUdpTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+
+            name = "SvgTool";
+            control = new SvgTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+
+            name = "AboutUsTool";
+            control = new AboutUsTool();
+            source = new Source { Title = name, UserControl = control };
+            Sources.AddOrUpdate(name, source, (k, v) => source);
+            UserControls.AddOrUpdate(name, control, (k, v) => control);
+
+            if (!TabControlItemsSource.Contains(source)) { TabControlItemsSource.Add(source); }
+            TabControlSelectedItem = source;
+        }
 
         /// <summary>
-        /// 控件集合
+        /// 控件集合,提前加载
         /// </summary>
         private ConcurrentDictionary<string, UserControl> UserControls = new ConcurrentDictionary<string, UserControl>();
-
-
+        /// <summary>
+        /// 数据源集合
+        /// </summary>
+        private ConcurrentDictionary<string, Source> Sources = new ConcurrentDictionary<string, Source>();
 
         /// <summary>
         /// 选项卡控件项源
@@ -261,5 +300,13 @@ namespace YSAI.Tool
             get => GetProperty(() => TabControlItemsSource);
             set => SetProperty(() => TabControlItemsSource, value);
         }
+        /// <summary>
+        /// 选中的项
+        /// </summary>
+        public Source TabControlSelectedItem
+        {
+            get => GetProperty(() => TabControlSelectedItem);
+            set => SetProperty(() => TabControlSelectedItem, value);
+        }
     }
 }

+ 3 - 4
src/YSAI.Ver.Manage.Tool/Program.cs

@@ -16,23 +16,22 @@ List<string> strings = new List<string>
     //"YSAI.Rpc",
     //"YSAI.Redis",
 
-    //"YSAI.Kafka",
+    "YSAI.Kafka",
     //"YSAI.Mqtt",
     //"YSAI.NetMQ",
     //"YSAI.Netty",
     //"YSAI.RabbitMQ",
-    //////////"YSAI.Rest",
 
     //"YSAI.AllenBradley",
     //"YSAI.Beckhoff",
     //"YSAI.Can",
     //"YSAI.DB",
     //"YSAI.Mewtocol",
-    "YSAI.Mitsubishi",
+    //"YSAI.Mitsubishi",
     //"YSAI.Modbus",
     //"YSAI.Omron",
     //"YSAI.Opc",
-    //"YSAI.Siemens",
+    "YSAI.Siemens",
 
 #endif
 };

+ 1 - 0
src/YSAI.Window/Themes/Style/ButtonStyle.xaml

@@ -419,4 +419,5 @@
             </MultiTrigger>
         </ControlTemplate.Triggers>
     </ControlTemplate>
+
 </ResourceDictionary>