瀏覽代碼

20250722001 开发同步

向羽 孟 2 月之前
父節點
當前提交
129d8453ed
共有 69 個文件被更改,包括 4709 次插入335 次删除
  1. 6 6
      CCDCount.sln
  2. 30 0
      CCDCountWpf/App.config
  3. 8 0
      CCDCountWpf/App.xaml
  4. 40 0
      CCDCountWpf/App.xaml.cs
  5. 247 0
      CCDCountWpf/CCDCountWpf.csproj
  6. 二進制
      CCDCountWpf/FromImage/PLC信息管理.png
  7. 二進制
      CCDCountWpf/FromImage/export.png
  8. 二進制
      CCDCountWpf/FromImage/mmexport1752891278116.jpg
  9. 二進制
      CCDCountWpf/FromImage/print.png
  10. 二進制
      CCDCountWpf/FromImage/中断.png
  11. 二進制
      CCDCountWpf/FromImage/刷新.png
  12. 二進制
      CCDCountWpf/FromImage/故障.png
  13. 二進制
      CCDCountWpf/FromImage/数据.png
  14. 二進制
      CCDCountWpf/FromImage/暂停.png
  15. 二進制
      CCDCountWpf/FromImage/用户修改.png
  16. 二進制
      CCDCountWpf/FromImage/用户删除.png
  17. 二進制
      CCDCountWpf/FromImage/用户增加.png
  18. 二進制
      CCDCountWpf/FromImage/用户管理.png
  19. 二進制
      CCDCountWpf/FromImage/相机小.png
  20. 二進制
      CCDCountWpf/FromImage/设置.png
  21. 二進制
      CCDCountWpf/FromImage/运行.png
  22. 二進制
      CCDCountWpf/FromImage/退出.png
  23. 52 0
      CCDCountWpf/Properties/AssemblyInfo.cs
  24. 71 0
      CCDCountWpf/Properties/Resources.Designer.cs
  25. 117 0
      CCDCountWpf/Properties/Resources.resx
  26. 30 0
      CCDCountWpf/Properties/Settings.Designer.cs
  27. 7 0
      CCDCountWpf/Properties/Settings.settings
  28. 855 0
      CCDCountWpf/ShowBindingClass.cs
  29. 59 0
      CCDCountWpf/WpfFrom/AddUserWindow.xaml
  30. 74 0
      CCDCountWpf/WpfFrom/AddUserWindow.xaml.cs
  31. 79 0
      CCDCountWpf/WpfFrom/ChangeUserWindow.xaml
  32. 108 0
      CCDCountWpf/WpfFrom/ChangeUserWindow.xaml.cs
  33. 69 0
      CCDCountWpf/WpfFrom/MainWindow.xaml
  34. 450 0
      CCDCountWpf/WpfFrom/MainWindow.xaml.cs
  35. 18 0
      CCDCountWpf/WpfFrom/SplashWindow.xaml
  36. 27 0
      CCDCountWpf/WpfFrom/SplashWindow.xaml.cs
  37. 62 0
      CCDCountWpf/WpfFrom/UserLoginWindow.xaml
  38. 62 0
      CCDCountWpf/WpfFrom/UserLoginWindow.xaml.cs
  39. 93 0
      CCDCountWpf/WpfPage/MainPage.xaml
  40. 82 0
      CCDCountWpf/WpfPage/MainPage.xaml.cs
  41. 23 0
      CCDCountWpf/WpfPage/MessagePage.xaml
  42. 29 0
      CCDCountWpf/WpfPage/MessagePage.xaml.cs
  43. 14 0
      CCDCountWpf/WpfPage/PlcSettingPage.xaml
  44. 28 0
      CCDCountWpf/WpfPage/PlcSettingPage.xaml.cs
  45. 147 0
      CCDCountWpf/WpfPage/SettingPage.xaml
  46. 268 0
      CCDCountWpf/WpfPage/SettingPage.xaml.cs
  47. 51 0
      CCDCountWpf/WpfPage/UserManagementPage.xaml
  48. 81 0
      CCDCountWpf/WpfPage/UserManagementPage.xaml.cs
  49. 9 0
      CCDCountWpf/packages.config
  50. 38 0
      TestWork.DLL/CCDCount.DLL.csproj
  51. 68 25
      TestWork.DLL/CameraClass.cs
  52. 109 0
      TestWork.DLL/FaultLogClass.cs
  53. 338 176
      TestWork.DLL/MainThreadClass.cs
  54. 6 6
      TestWork.DLL/MechanicalControlClass.cs
  55. 41 26
      TestWork.DLL/ShuLiClass.cs
  56. 104 0
      TestWork.DLL/SqlDataClass/ErrorMesSqliteDataClass.cs
  57. 268 0
      TestWork.DLL/SqlDataClass/UserMessSqliteDataClass.cs
  58. 175 0
      TestWork.DLL/Tools/ModbusClass.cs
  59. 40 0
      TestWork.DLL/Tools/SystemMonitorClass.cs
  60. 16 0
      TestWork.DLL/app.config
  61. 7 0
      TestWork.DLL/packages.config
  62. 3 0
      TestWork.MODEL/CCDCount.MODEL.csproj
  63. 15 0
      TestWork.MODEL/ConfigModel/SaveConfigModel.cs
  64. 40 0
      TestWork.MODEL/SqlDataModel/ErroeMesDataModelClass.cs
  65. 19 0
      TestWork.MODEL/SqlDataModel/UserMesDataModelClass.cs
  66. 2 0
      TestWork/CCDCount.csproj
  67. 6 20
      TestWork/Forms/MainForm.cs
  68. 75 76
      TestWork/Forms/SettingForm.cs
  69. 43 0
      TestWork/ShowBindingClass.cs

+ 6 - 6
CCDCount.sln

@@ -3,22 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio Version 17
 VisualStudioVersion = 17.13.35931.197
 MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCDCount", "TestWork\CCDCount.csproj", "{9330D238-A8F6-4C89-B70A-99380789B1B1}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCDCount.DLL", "TestWork.DLL\CCDCount.DLL.csproj", "{E7F2647E-07D6-41F2-81FD-FA32DA6D2526}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCDCount.MODEL", "TestWork.MODEL\CCDCount.MODEL.csproj", "{C230B744-CABC-4B34-80BB-2CEE55A8B2B9}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CCDCountWpf", "CCDCountWpf\CCDCountWpf.csproj", "{DCCBE504-5801-442E-A406-4A7099D46553}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{9330D238-A8F6-4C89-B70A-99380789B1B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{9330D238-A8F6-4C89-B70A-99380789B1B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{9330D238-A8F6-4C89-B70A-99380789B1B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{9330D238-A8F6-4C89-B70A-99380789B1B1}.Release|Any CPU.Build.0 = Release|Any CPU
 		{E7F2647E-07D6-41F2-81FD-FA32DA6D2526}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{E7F2647E-07D6-41F2-81FD-FA32DA6D2526}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{E7F2647E-07D6-41F2-81FD-FA32DA6D2526}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -27,6 +23,10 @@ Global
 		{C230B744-CABC-4B34-80BB-2CEE55A8B2B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{C230B744-CABC-4B34-80BB-2CEE55A8B2B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{C230B744-CABC-4B34-80BB-2CEE55A8B2B9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DCCBE504-5801-442E-A406-4A7099D46553}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DCCBE504-5801-442E-A406-4A7099D46553}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DCCBE504-5801-442E-A406-4A7099D46553}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DCCBE504-5801-442E-A406-4A7099D46553}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 30 - 0
CCDCountWpf/App.config

@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <configSections>
+    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+  </configSections>
+  <startup>
+    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
+  </startup>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+  <entityFramework>
+    <providers>
+      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
+    </providers>
+  </entityFramework>
+  <system.data>
+    <DbProviderFactories>
+      <remove invariant="System.Data.SQLite.EF6" />
+      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
+    <remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories>
+  </system.data>
+</configuration>

+ 8 - 0
CCDCountWpf/App.xaml

@@ -0,0 +1,8 @@
+<Application x:Class="CCDCountWpf.App"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:local="clr-namespace:CCDCountWpf" StartupUri="/WpfFrom/UserLoginWindow.xaml">
+    <Application.Resources>
+         
+    </Application.Resources>
+</Application>

+ 40 - 0
CCDCountWpf/App.xaml.cs

@@ -0,0 +1,40 @@
+using CCDCount.DLL;
+using CCDCount.DLL.SqlDataClass;
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Threading;
+
+namespace CCDCountWpf
+{
+    public static class MessageBus
+    {
+        public static List<MainThreadClass> MainThreadS = new List<MainThreadClass>();
+
+        public static MainThreadClass NowSettingLoadMainThread = null;
+
+        public static ShowBindingClass ShowBinding = new ShowBindingClass();
+
+        public static CameraClass CameraClass = new CameraClass();
+
+        public static UserMessSqliteDataClass UserMessageClass = new UserMessSqliteDataClass($"{AppDomain.CurrentDomain.BaseDirectory}DATA\\UserData\\UserMessage.db");
+
+        public static UserMesDataModelClass NowLoginUserMessage = null;
+
+        public static string NowLoadCammeraSN = string.Empty;
+        public static int SeetingNowLoadInMaThreadsIndex = -1;
+        public static int NowLoadCameraIndex = -1;
+    }
+    /// <summary>
+    /// App.xaml 的交互逻辑
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}

+ 247 - 0
CCDCountWpf/CCDCountWpf.csproj

@@ -0,0 +1,247 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{DCCBE504-5801-442E-A406-4A7099D46553}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>CCDCountWpf</RootNamespace>
+    <AssemblyName>CCDCountWpf</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>x64</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
+    <Reference Include="MvCameraControl.Net, Version=4.3.2.2, Culture=neutral, PublicKeyToken=a3c7c5e3a730cd12, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\TestWork.DLL\DLL\MvCameraControl.Net.dll</HintPath>
+    </Reference>
+    <Reference Include="MvFGCtrlC.Net, Version=1.0.0.0, Culture=neutral, PublicKeyToken=52fddfb3f94be800, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\TestWork.DLL\DLL\MvFGCtrlC.Net.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Data.SQLite, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\lib\net46\System.Data.SQLite.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.EF6, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Data.SQLite.EF6.1.0.119.0\lib\net46\System.Data.SQLite.EF6.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.Linq, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Data.SQLite.Linq.1.0.119.0\lib\net46\System.Data.SQLite.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+  </ItemGroup>
+  <ItemGroup>
+    <ApplicationDefinition Include="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </ApplicationDefinition>
+    <Compile Include="WpfFrom\AddUserWindow.xaml.cs">
+      <DependentUpon>AddUserWindow.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfFrom\ChangeUserWindow.xaml.cs">
+      <DependentUpon>ChangeUserWindow.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfFrom\SplashWindow.xaml.cs">
+      <DependentUpon>SplashWindow.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfFrom\UserLoginWindow.xaml.cs">
+      <DependentUpon>UserLoginWindow.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfPage\MessagePage.xaml.cs">
+      <DependentUpon>MessagePage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfPage\PlcSettingPage.xaml.cs">
+      <DependentUpon>PlcSettingPage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfPage\SettingPage.xaml.cs">
+      <DependentUpon>SettingPage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfPage\UserManagementPage.xaml.cs">
+      <DependentUpon>UserManagementPage.xaml</DependentUpon>
+    </Compile>
+    <Page Include="WpfFrom\AddUserWindow.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfFrom\ChangeUserWindow.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfFrom\SplashWindow.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfFrom\UserLoginWindow.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfPage\MainPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfFrom\MainWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Compile Include="App.xaml.cs">
+      <DependentUpon>App.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="ShowBindingClass.cs" />
+    <Compile Include="WpfPage\MainPage.xaml.cs">
+      <DependentUpon>MainPage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="WpfFrom\MainWindow.xaml.cs">
+      <DependentUpon>MainWindow.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Page Include="WpfPage\MessagePage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfPage\PlcSettingPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfPage\SettingPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="WpfPage\UserManagementPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\数据.png" />
+    <Resource Include="FromImage\相机小.png" />
+    <Resource Include="FromImage\设置.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\退出.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\中断.png" />
+    <Resource Include="FromImage\运行.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\TestWork.DLL\CCDCount.DLL.csproj">
+      <Project>{e7f2647e-07d6-41f2-81fd-fa32da6d2526}</Project>
+      <Name>CCDCount.DLL</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\TestWork.MODEL\CCDCount.MODEL.csproj">
+      <Project>{c230b744-cabc-4b34-80bb-2cee55a8b2b9}</Project>
+      <Name>CCDCount.MODEL</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\刷新.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\暂停.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\故障.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\export.png" />
+    <Resource Include="FromImage\print.png" />
+    <Resource Include="FromImage\用户修改.png" />
+    <Resource Include="FromImage\用户删除.png" />
+    <Resource Include="FromImage\用户增加.png" />
+    <Resource Include="FromImage\用户管理.png" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\mmexport1752891278116.jpg" />
+  </ItemGroup>
+  <ItemGroup>
+    <Resource Include="FromImage\PLC信息管理.png" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
+    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
+    <Error Condition="!Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets'))" />
+  </Target>
+  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
+  <Import Project="..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets" Condition="Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" />
+</Project>

二進制
CCDCountWpf/FromImage/PLC信息管理.png


二進制
CCDCountWpf/FromImage/export.png


二進制
CCDCountWpf/FromImage/mmexport1752891278116.jpg


二進制
CCDCountWpf/FromImage/print.png


二進制
CCDCountWpf/FromImage/中断.png


二進制
CCDCountWpf/FromImage/刷新.png


二進制
CCDCountWpf/FromImage/故障.png


二進制
CCDCountWpf/FromImage/数据.png


二進制
CCDCountWpf/FromImage/暂停.png


二進制
CCDCountWpf/FromImage/用户修改.png


二進制
CCDCountWpf/FromImage/用户删除.png


二進制
CCDCountWpf/FromImage/用户增加.png


二進制
CCDCountWpf/FromImage/用户管理.png


二進制
CCDCountWpf/FromImage/相机小.png


二進制
CCDCountWpf/FromImage/设置.png


二進制
CCDCountWpf/FromImage/运行.png


二進制
CCDCountWpf/FromImage/退出.png


+ 52 - 0
CCDCountWpf/Properties/AssemblyInfo.cs

@@ -0,0 +1,52 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("CCDCountWpf")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CCDCountWpf")]
+[assembly: AssemblyCopyright("Copyright ©  2025")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+//若要开始生成可本地化的应用程序,请设置
+//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
+//在 <PropertyGroup> 中。例如,如果你使用的是美国英语。
+//使用的是美国英语,请将 <UICulture> 设置为 en-US。  然后取消
+//对以下 NeutralResourceLanguage 特性的注释。  更新
+//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+    ResourceDictionaryLocation.None, //主题特定资源词典所处位置
+                                     //(未在页面中找到资源时使用,
+                                     //或应用程序资源字典中找到时使用)
+    ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
+                                              //(未在页面中找到资源时使用,
+                                              //、应用程序或任何主题专用资源字典中找到时使用)
+)]
+
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 71 - 0
CCDCountWpf/Properties/Resources.Designer.cs

@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本: 4.0.30319.42000
+//
+//     对此文件的更改可能导致不正确的行为,如果
+//     重新生成代码,则所做更改将丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CCDCountWpf.Properties
+{
+
+
+    /// <summary>
+    ///   强类型资源类,用于查找本地化字符串等。
+    /// </summary>
+    // 此类是由 StronglyTypedResourceBuilder
+    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+    // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+    // (以 /str 作为命令选项),或重新生成 VS 项目。
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   返回此类使用的缓存 ResourceManager 实例。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CCDCountWpf.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   重写当前线程的 CurrentUICulture 属性,对
+        ///   使用此强类型资源类的所有资源查找执行重写。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
CCDCountWpf/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 30 - 0
CCDCountWpf/Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace CCDCountWpf.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+    {
+
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+        public static Settings Default
+        {
+            get
+            {
+                return defaultInstance;
+            }
+        }
+    }
+}

+ 7 - 0
CCDCountWpf/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 855 - 0
CCDCountWpf/ShowBindingClass.cs

@@ -0,0 +1,855 @@
+using CCDCount.DLL;
+using CCDCount.MODEL.ConfigModel;
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Drawing.Text;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace CCDCountWpf
+{
+    public class CameraCoboxItem
+    {
+        public string Name { get; set; }  // 显示的名称
+        public string SNValue { get; set; }  // 对应的编号
+    }
+
+    public class ShowBindingClass : INotifyPropertyChanged
+    {
+        /// <summary>
+        /// 累计数量
+        /// </summary>
+        private string allActiveNum = "0";
+        public string AllActiveNum
+        {
+            get { return allActiveNum; }
+            set
+            {
+                allActiveNum = value;
+                OnPropertyChanged("AllActiveNum");
+            }
+        }
+
+        /// <summary>
+        /// 累计OK
+        /// </summary>
+        private string allOkNum = "0";
+        public string AllOkNum
+        {
+            get { return allOkNum; }
+            set
+            {
+                allOkNum = value;
+                OnPropertyChanged("AllOkNum");
+            }
+        }
+
+        /// <summary>
+        /// 累计NG
+        /// </summary>
+        private string allNgNum = "0";
+        public string AllNgNum
+        {
+            get { return allNgNum; }
+            set
+            {
+                allNgNum = value;
+                OnPropertyChanged("AllNgNum");
+            }
+        }
+
+        /// <summary>
+        /// 数粒速度
+        /// </summary>
+        private string shuLiSpeed = "0";
+        public string ShuLiSpeed
+        {
+            get { return shuLiSpeed; }
+            set
+            {
+                shuLiSpeed = value;
+                OnPropertyChanged("ShuLiSpeed");
+            }
+        }
+
+        /// <summary>
+        /// 内存监控
+        /// </summary>
+        private string ramMonitor = "";
+        public string RamMonitor
+        {
+            get { return ramMonitor; }
+            set
+            {
+                ramMonitor = value;
+                OnPropertyChanged("RamMonitor");
+            }
+        }
+
+        /// <summary>
+        /// CPU监控
+        /// </summary>
+        private string _CPUMonitor = "";
+        public string CPUMonitor
+        {
+            get { return _CPUMonitor; }
+            set
+            {
+                _CPUMonitor = value;
+                OnPropertyChanged("CPUMonitor");
+            }
+        }
+
+        /// <summary>
+        /// 相机运行状态
+        /// </summary>
+        private string camRunStatic = "未运行";
+        public string CamRunStatic
+        {
+            get { return camRunStatic; }
+            set
+            {
+                camRunStatic = value;
+                OnPropertyChanged("CamRunStatic");
+            }
+        }
+
+        /// <summary>
+        /// 结果图像
+        /// </summary>
+        private BitmapImage bitmapImage;
+        public BitmapImage BitmapImage
+        {
+            get { return bitmapImage; }
+            set
+            {
+                bitmapImage = value;
+                OnPropertyChanged("BitmapImage");
+            }
+        }
+
+        // <summary>
+        /// 缩略图1
+        /// </summary>
+        private BitmapImage thumbnailImage1;
+        public BitmapImage ThumbnailImage1
+        {
+            get { return thumbnailImage1; }
+            set
+            {
+                thumbnailImage1 = value;
+                OnPropertyChanged("ThumbnailImage1");
+            }
+        }
+
+        // <summary>
+        /// 缩略图2
+        /// </summary>
+        private BitmapImage thumbnailImage2;
+        public BitmapImage ThumbnailImage2
+        {
+            get { return thumbnailImage2; }
+            set
+            {
+                thumbnailImage2 = value;
+                OnPropertyChanged("ThumbnailImage2");
+            }
+        }
+
+        // <summary>
+        /// 缩略图3
+        /// </summary>
+        private BitmapImage thumbnailImage3;
+        public BitmapImage ThumbnailImage3
+        {
+            get { return thumbnailImage3; }
+            set
+            {
+                thumbnailImage3 = value;
+                OnPropertyChanged("ThumbnailImage3");
+            }
+        }
+
+        // <summary>
+        /// 缩略图4
+        /// </summary>
+        private BitmapImage thumbnailImage4;
+        public BitmapImage ThumbnailImage4
+        {
+            get { return thumbnailImage4; }
+            set
+            {
+                thumbnailImage4 = value;
+                OnPropertyChanged("ThumbnailImage4");
+            }
+        }
+
+        /// <summary>
+        /// 相机运行状态字体颜色
+        /// </summary>
+        private SolidColorBrush cameraStaticColor = Brushes.Red;
+        public SolidColorBrush CameraStaticColor
+        {
+            get { return cameraStaticColor; }
+            set
+            {
+                cameraStaticColor = value;
+                OnPropertyChanged("CameraStaticColor");
+            }
+        }
+
+        /// <summary>
+        /// 相机曝光时间
+        /// </summary>
+        public string ExposureTimeValue
+        {
+            get
+            {
+                // 从MessageBus获取最新值(保证读取时同步)
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.ExposureTimeValue.ToString();
+                }
+                return "";
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null && float.TryParse(value, out float newValue))
+                {
+                    // 同步更新到MessageBus
+                    float oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.ExposureTimeValue;
+                    MessageBus.NowSettingLoadMainThread.cameraConfig.ExposureTimeValue = newValue;
+                    MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                    FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的曝光时间已从{oldValue}修改为{newValue}");
+                    OnPropertyChanged("ExposureTimeValue");
+                }
+            }
+        }
+
+        /// <summary>
+        /// 相机行频
+        /// </summary>
+        public string AcquistionLineRate
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.AcquistionLineRateValue.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set 
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        float oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.AcquistionLineRateValue;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.AcquistionLineRateValue = int.Parse(value);
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的行频从{oldValue}修改为{value}");
+                        OnPropertyChanged("AcquistionLineRate");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("AcquistionLineRate-SetError");
+                    }
+                    
+                }
+            }
+        }
+
+        /// <summary>
+        /// 图像高度
+        /// </summary>
+        public string ImageHeight
+        {
+            get
+            {
+                if(MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.Height.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.Height;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.Height = int.Parse(value);
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的图像高从{oldValue}修改为{value}");
+                        OnPropertyChanged("ImageHeight");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("ImageHeight-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 图像宽度
+        /// </summary>
+        public string ImageWidth
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.Width.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.Width;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.Width = int.Parse(value);
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的图像宽从{oldValue}修改为{value}");
+                        OnPropertyChanged("ImageWidth");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("ImageWidth-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 相机名称(用户自定义)
+        /// </summary>
+        public string CamUserName
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.CameraName;
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        string oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraName == "" ? "null" : MessageBus.NowSettingLoadMainThread.cameraConfig.CameraName;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.CameraName = value;
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的用户自定义名从{oldValue}修改为{value}");
+                        OnPropertyChanged("CamUserName");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("CamUserName-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 图像偏移X
+        /// </summary>
+        public string CamOffsetX
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.OffsetX.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.OffsetX;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.OffsetX = int.Parse(value);
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的图像X偏移从{oldValue}修改为{value}");
+                        OnPropertyChanged("CamOffsetX");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("CamOffsetX-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 相机列表
+        /// </summary>
+        public ObservableCollection<CameraCoboxItem> CameraItems { get; } = new ObservableCollection<CameraCoboxItem>();
+
+        /// <summary>
+        /// 当前选择的相机SN
+        /// </summary>
+        public string CameraSNNum
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        string oldValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+                        MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum = value;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.CameraSN = value;
+                        MessageBus.NowSettingLoadMainThread.CameraConfigIsChange = true;
+                        FaultLog.RecordValueChangeMessage($"相机{MessageBus.NowSettingLoadMainThread.cameraConfig.CamerNo}的SN从{oldValue}修改为{value}");
+                        OnPropertyChanged("CameraSNNum");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("CameraSNNum-SetError");
+                    }
+
+                }
+            }
+        }
+        /// <summary>
+        /// 预处理阈值
+        /// </summary>
+        public string RegionThreshold
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.RegionThreshold.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.RegionThreshold;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.RegionThreshold = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的预处理阈值从{oldValue}修改为{value}");
+                        OnPropertyChanged("RegionThreshold");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("RegionThreshold-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 数粒通道数
+        /// </summary>
+        public string Channel
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.Channel.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.Channel;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.Channel = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的通道数从{oldValue}修改为{value}");
+                        OnPropertyChanged("Channel");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("Channel-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 噪声滤波阈值
+        /// </summary>
+        public string NoiseFilter
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.NoiseFilter_Threshold.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.NoiseFilter_Threshold;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.NoiseFilter_Threshold = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的噪声滤波阈值从{oldValue}修改为{value}");
+                        OnPropertyChanged("NoiseFilter");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("NoiseFilter-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最小宽
+        /// </summary>
+        public string MIN_OBJECT_WIDTH
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_WIDTH.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_WIDTH;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_WIDTH = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最小宽从{oldValue}修改为{value}");
+                        OnPropertyChanged("MIN_OBJECT_WIDTH");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MIN_OBJECT_WIDTH-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最大宽
+        /// </summary>
+        public string MAX_OBJECT_WIDTH
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_WIDTH.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_WIDTH;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_WIDTH = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最大宽从{oldValue}修改为{value}");
+                        OnPropertyChanged("MAX_OBJECT_WIDTH");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MAX_OBJECT_WIDTH-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最小高
+        /// </summary>
+        public string MIN_OBJECT_HEIGHT
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_HEIGHT.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_HEIGHT;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MIN_OBJECT_HEIGHT = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最小高从{oldValue}修改为{value}");
+                        OnPropertyChanged("MIN_OBJECT_HEIGHT");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MIN_OBJECT_HEIGHT-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最大高
+        /// </summary>
+        public string MAX_OBJECT_HEIGHT
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_HEIGHT.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_HEIGHT;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MAX_OBJECT_HEIGHT = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最大高从{oldValue}修改为{value}");
+                        OnPropertyChanged("MAX_OBJECT_HEIGHT");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MAX_OBJECT_HEIGHT-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最小面积
+        /// </summary>
+        public string MinArea
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MinArea.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MinArea;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MinArea = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最小面积从{oldValue}修改为{value}");
+                        OnPropertyChanged("MinArea");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MinArea-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒最大面积
+        /// </summary>
+        public string MaxArea
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MaxArea.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.MaxArea;
+                        MessageBus.NowSettingLoadMainThread.shuLiConfig.MaxArea = int.Parse(value);
+                        FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的异常粒最大面积从{oldValue}修改为{value}");
+                        OnPropertyChanged("MaxArea");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("MaxArea-SetError");
+                    }
+
+                }
+            }
+        }
+
+        /// <summary>
+        /// 异常粒识别码
+        /// </summary>
+        public string PandingCode
+        {
+            get
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    return MessageBus.NowSettingLoadMainThread.shuLiConfig.MaxArea.ToString();
+                }
+                else
+                {
+                    return "";
+                }
+            }
+            set
+            {
+                if (MessageBus.NowSettingLoadMainThread != null)
+                {
+                    try
+                    {
+                        int oldValue = MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode;
+                        if(oldValue != int.Parse(value))
+                        {
+                            MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode = int.Parse(value);
+                            FaultLog.RecordValueChangeMessage($"数粒识别{MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum}的判断标准识别码从{oldValue}修改为{value}");
+                        }
+                        OnPropertyChanged("PandingCode");
+                    }
+                    catch (Exception)
+                    {
+                        Console.WriteLine("PandingCode-SetError");
+                    }
+
+                }
+            }
+        }
+
+        private List<ErroeMesDataModelClass> errMessageList = new List<ErroeMesDataModelClass>();
+        public List<ErroeMesDataModelClass> ErrMessageShowList
+        {
+            get { return errMessageList; }
+            set
+            {
+                errMessageList = value;
+                OnPropertyChanged("errMessageList");
+            }
+        }
+
+        private List<UserMesDataModelClass> userMesDataModels = new List<UserMesDataModelClass>();
+        public List<UserMesDataModelClass> UserMesDataModels
+        {
+            get { return userMesDataModels; }
+            set
+            {
+                userMesDataModels = value;
+                OnPropertyChanged("userMesDataModels");
+            }
+        }
+
+        //数据绑定核心实现
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected void OnPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}

+ 59 - 0
CCDCountWpf/WpfFrom/AddUserWindow.xaml

@@ -0,0 +1,59 @@
+<Window x:Class="CCDCountWpf.WpfFrom.AddUserWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:CCDCountWpf.WpfFrom"
+        mc:Ignorable="d"
+        Title="AddUserWindow" Height="350" Width="300" ResizeMode="NoResize"
+        WindowStartupLocation="CenterScreen" Icon="/FromImage/mmexport1752891278116.jpg" Loaded="Window_Loaded">
+    <Grid>
+        <Grid Height="60" VerticalAlignment="Top" Background="#B20092FF">
+            <Label Content="添加用户" Margin="0,15,0,0" FontWeight="Bold" FontSize="20" VerticalAlignment="Top" HorizontalAlignment="Center"/>
+        </Grid>
+        <StackPanel Orientation="Vertical" Margin="0,60,0,0">
+            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="19,0,0,0">
+                <Label  Content="用户名:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <TextBox x:Name="UserNameTbx" HorizontalAlignment="Left" Margin="22,15,0,0"  Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"/>
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="19,0,0,0">
+                <Label  Content="密码:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <PasswordBox x:Name="UserPassTbx"  HorizontalAlignment="Left" Margin="41,15,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="19,0,0,0">
+                <Label  Content="确认密码:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <PasswordBox x:Name="UserRePassTbx"  HorizontalAlignment="Left" Margin="0,15,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="19,0,0,0">
+                <Label  Content="权限:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <ComboBox x:Name="UserLevelCbx" HorizontalAlignment="Left" Margin="41,12,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}" IsReadOnly="True"/>
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
+                <Button x:Name="AddUserBtn" Content="添加" BorderThickness="1" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="AddUserBtn_Click" Cursor="Hand">
+                    <Button.Template>
+                        <ControlTemplate TargetType="Button">
+                            <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                            </Border>
+                        </ControlTemplate>
+                    </Button.Template>
+                </Button>
+                <Button x:Name="UserCancelBtn" Content="取消" BorderThickness="1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserCancelBtn_Click" Cursor="Hand">
+                    <Button.Template>
+                        <ControlTemplate TargetType="Button">
+                            <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                            </Border>
+                        </ControlTemplate>
+                    </Button.Template>
+                </Button>
+            </StackPanel>
+        </StackPanel>
+    </Grid>
+</Window>

+ 74 - 0
CCDCountWpf/WpfFrom/AddUserWindow.xaml.cs

@@ -0,0 +1,74 @@
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf.WpfFrom
+{
+    /// <summary>
+    /// AddUserWindow.xaml 的交互逻辑
+    /// </summary>
+    public partial class AddUserWindow : Window
+    {
+        public AddUserWindow()
+        {
+            InitializeComponent();
+        }
+
+        private void UserCancelBtn_Click(object sender, RoutedEventArgs e)
+        {
+            this.Close();
+        }
+
+        private void AddUserBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (UserNameTbx.Text == "" || UserPassTbx.Password == "" || UserRePassTbx.Password == "" || UserLevelCbx.SelectedItem == null)
+            {
+                MessageBox.Show("请将信息填写完整");
+                return;
+            }
+            if (MessageBus.ShowBinding.UserMesDataModels.Where(x => x.UserName == UserNameTbx.Text).Count() > 0)
+            {
+                MessageBox.Show("用户名已存在");
+                return;
+            }
+            if (UserPassTbx.Password == UserRePassTbx.Password)
+            {
+                MessageBus.UserMessageClass.InsertUserMessage(new UserMesDataModelClass()
+                {
+                    UserName = UserNameTbx.Text,
+                    PassWord = UserPassTbx.Password,
+                    UserMes = UserLevelCbx.SelectedItem.ToString(),
+                    DateTime = DateTime.Now,
+                    IsDelete = false,
+                    IsAdmin = UserLevelCbx.SelectedItem.ToString() == "管理员" ? true : false
+                });
+            }
+            else
+            {
+                MessageBox.Show("密码不一致");
+                return;
+            }
+            MessageBox.Show("添加成功");
+            MessageBus.ShowBinding.UserMesDataModels = MessageBus.UserMessageClass.GetAllUserMessage();
+            this.Close();
+        }
+
+        private void Window_Loaded(object sender, RoutedEventArgs e)
+        {
+            UserLevelCbx.Items.Add("管理员");
+            UserLevelCbx.Items.Add("普通用户");
+            UserLevelCbx.SelectedIndex = 1;
+        }
+    }
+}

+ 79 - 0
CCDCountWpf/WpfFrom/ChangeUserWindow.xaml

@@ -0,0 +1,79 @@
+<Window x:Class="CCDCountWpf.WpfFrom.ChangeUserWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:CCDCountWpf.WpfFrom"
+        mc:Ignorable="d"
+        Title="ChangeUserWindow" Height="430" Width="320" ResizeMode="NoResize"
+        WindowStartupLocation="CenterScreen" Icon="/FromImage/mmexport1752891278116.jpg" Loaded="Window_Loaded">
+    <Grid>
+        <Grid Height="60" VerticalAlignment="Top" Background="#B20092FF">
+            <Label Content="编辑用户" Margin="0,15,0,0" FontWeight="Bold" FontSize="20" VerticalAlignment="Top" HorizontalAlignment="Center"/>
+        </Grid>
+        <StackPanel Orientation="Vertical" Margin="0,60,0,0">
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="30,0,0,0">
+                <Label  Content="ID:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <TextBox x:Name="UserIDTbx" HorizontalAlignment="Left" Margin="77,15,0,0"  Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}" IsReadOnly="True"/>
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="30,0,0,0">
+                <Label  Content="用户名:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <TextBox x:Name="UserNameTbx" HorizontalAlignment="Left" Margin="40,15,0,0"  Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"/>
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="30,0,0,0">
+                <Label  Content="旧密码:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <PasswordBox x:Name="UserOldPassTbx"  HorizontalAlignment="Left" Margin="40,15,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="30,0,0,0">
+                <Label  Content="新密码:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <PasswordBox x:Name="UserNewPassTbx"  HorizontalAlignment="Left" Margin="40,15,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="30,0,0,0">
+                <Label  Content="重复新密码:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <PasswordBox x:Name="UserReNewPassTbx"  HorizontalAlignment="Left" Margin="0,15,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="19,0,0,0">
+                <Label  Content="权限:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                <ComboBox x:Name="UserLevelCbx" HorizontalAlignment="Left" Margin="61,12,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}" IsReadOnly="True"/>
+            </StackPanel>
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
+                <Button x:Name="UserChangeBtn" Content="修改" BorderThickness="1" HorizontalAlignment="Left" Margin="0,10,10,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserChangeBtn_Click" Cursor="Hand">
+                    <Button.Template>
+                        <ControlTemplate TargetType="Button">
+                            <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                            </Border>
+                        </ControlTemplate>
+                    </Button.Template>
+                </Button>
+                <Button x:Name="UserResetPassBtn" Content="密码重置" BorderThickness="1" HorizontalAlignment="Left" Margin="5,10,5,0" VerticalAlignment="Top" Width="100" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserResetPassBtn_Click" Cursor="Hand">
+                    <Button.Template>
+                        <ControlTemplate TargetType="Button">
+                            <Border CornerRadius="5" 
+                        Background="{TemplateBinding Background}"
+                        BorderBrush="{TemplateBinding BorderBrush}"
+                        BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                            </Border>
+                        </ControlTemplate>
+                    </Button.Template>
+                </Button>
+                <Button x:Name="UserCancelBtn" Content="取消" BorderThickness="1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserCancelBtn_Click" Cursor="Hand">
+                    <Button.Template>
+                        <ControlTemplate TargetType="Button">
+                            <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                            </Border>
+                        </ControlTemplate>
+                    </Button.Template>
+                </Button>
+            </StackPanel>
+        </StackPanel>
+    </Grid>
+</Window>

+ 108 - 0
CCDCountWpf/WpfFrom/ChangeUserWindow.xaml.cs

@@ -0,0 +1,108 @@
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf.WpfFrom
+{
+    /// <summary>
+    /// ChangeUserWindow.xaml 的交互逻辑
+    /// </summary>
+    public partial class ChangeUserWindow : Window
+    {
+        public UserMesDataModelClass UserMessage = null;
+        public ChangeUserWindow()
+        {
+            InitializeComponent();
+        }
+
+        private void UserCancelBtn_Click(object sender, RoutedEventArgs e)
+        {
+            this.Close();
+        }
+
+        private void UserChangeBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (UserMessage == null) return;
+            if (UserNameTbx.Text == "" || UserOldPassTbx.Password == "" || UserNewPassTbx.Password == "" 
+                || UserReNewPassTbx.Password == "" || UserLevelCbx.SelectedItem == null)
+            {
+                MessageBox.Show("请将信息填写完整");
+                return;
+            }
+            string OldPass = MessageBus.UserMessageClass.HashPassword(UserOldPassTbx.Password);
+            if (OldPass != UserMessage.PassWord)
+            {
+                MessageBox.Show("旧密码输入错误");
+                return;
+            }
+            if (UserReNewPassTbx.Password != UserNewPassTbx.Password)
+            {
+                MessageBox.Show("新密码输入不一致");
+                return;
+            }
+            if(MessageBus.ShowBinding.UserMesDataModels.Where(x => x.UserName == UserNameTbx.Text).Count() > 0)
+            {
+                MessageBox.Show("用户名已存在");
+                return;
+            }
+            UserMesDataModelClass newUserMessage = new UserMesDataModelClass()
+            {
+                Id = UserMessage.Id,
+                UserName = UserNameTbx.Text,
+                PassWord = UserNewPassTbx.Password,
+                IsDelete = UserMessage.IsDelete,
+                IsAdmin = UserLevelCbx.SelectedItem.ToString() == "管理员" ? true : false,
+                UserMes = UserLevelCbx.SelectedItem.ToString()
+            };
+            MessageBus.UserMessageClass.ChangeUserMessage(UserMessage.Id, newUserMessage);
+            MessageBus.ShowBinding.UserMesDataModels = MessageBus.UserMessageClass.GetAllUserMessage();
+            MessageBox.Show("修改成功");
+            this.Close();
+        }
+
+        private void UserResetPassBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if(UserMessage == null) return;
+            var confirmResult = MessageBox.Show($"继续执行此操作将会重置用户{UserMessage.UserName}的密码至默认的\"123456\",是否继续执行",
+                                      "执行确认", MessageBoxButton.YesNo);
+            if (confirmResult == MessageBoxResult.No)
+            {
+                return;
+            }
+            MessageBus.UserMessageClass.ResetPassWord(UserMessage.Id);
+            MessageBus.ShowBinding.UserMesDataModels = MessageBus.UserMessageClass.GetAllUserMessage();
+            MessageBox.Show("重置成功");
+            UserMessage = MessageBus.ShowBinding.UserMesDataModels.Where(x => x.Id == UserMessage.Id).FirstOrDefault();
+        }
+
+        private void Window_Loaded(object sender, RoutedEventArgs e)
+        {
+            UserLevelCbx.Items.Clear();
+            if (UserMessage.IsAdmin && UserMessage.Id == 1)
+            {
+                UserLevelCbx.Items.Add("管理员");
+                UserLevelCbx.SelectedIndex = 0;
+                UserNameTbx.Text = UserMessage.UserName;
+                UserNameTbx.IsReadOnly = true;
+            }
+            else
+            {
+                UserLevelCbx.Items.Add("管理员");
+                UserLevelCbx.Items.Add("普通用户");
+                UserLevelCbx.SelectedItem = UserMessage.IsAdmin ? "管理员" : "普通用户";
+            }
+            UserIDTbx.Text = UserMessage.Id.ToString();
+        }
+    }
+}

+ 69 - 0
CCDCountWpf/WpfFrom/MainWindow.xaml

@@ -0,0 +1,69 @@
+<Window x:Class="CCDCountWpf.MainWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:CCDCountWpf"
+        mc:Ignorable="d"
+        Title="MainWindow" Height="720" Width="820" MinWidth="900" MinHeight="720" Closing="Window_Closing" WindowStartupLocation="CenterScreen" Icon="/FromImage/mmexport1752891278116.jpg">
+    <Grid Background="#B2E0E0E0">
+        <Grid  x:Name="HeardGrid" Height="60" VerticalAlignment="Top" Background="#B20092FF">
+            <Button x:Name="ExitBtn" HorizontalAlignment="Left" Height="60" Width="60" Click="ExitBtn_Click" Background="{x:Null}">
+                    <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                        <Image  Source="/FromImage/退出.png" Width="28" Height="28" />
+                        <TextBlock Text="系统退出" FontSize="10" FontWeight="Bold" Margin="0,8,0,0" HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+            <Button x:Name="MainPageBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="60,0,0,0" Background="{x:Null}" Click="MainPageBtn_Click">
+                    <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                        <Image  Source="/FromImage/相机小.png" Width="32" Height="32" />
+                        <TextBlock Text="主界面" FontSize="10" FontWeight="Bold" Margin="0,5,0,0" HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+            <Button x:Name="SettingBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="120,0,0,0" Background="{x:Null}" Click="SettingBtn_Click">
+                    <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                        <Image  Source="/FromImage/设置.png" Width="32" Height="32" />
+                        <TextBlock Text="设置界面" FontSize="10" FontWeight="Bold" Margin="0,5,0,0" HorizontalAlignment="Center" />
+                    </StackPanel>
+                </Button>
+            <Button x:Name="PlcSettingBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="180,0,0,0" Background="{x:Null}" Click="PlcSettingBtn_Click">
+                <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                    <Image  Source="/FromImage/PLC信息管理.png" Width="32" Height="32" />
+                    <TextBlock Text="PLC设置" FontSize="10" FontWeight="Bold" Margin="0,5,0,0" HorizontalAlignment="Center" />
+                </StackPanel>
+            </Button>
+            <Button x:Name="ErrorMessageShowBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="240,0,0,0" Background="{x:Null}" Click="ErrorMessageShowBtn_Click">
+                <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                    <Image  Source="/FromImage/故障.png" Width="36" Height="36" />
+                    <TextBlock Text="故障页面" FontSize="10" FontWeight="Bold" Margin="0,0,0,0" HorizontalAlignment="Center" />
+                </StackPanel>
+            </Button>
+            <Button x:Name="UserMessageBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="300,0,0,0" Background="{x:Null}" Click="UserMessageBtn_Click">
+                <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                    <Image  Source="/FromImage/用户管理.png" Width="32" Height="32" />
+                    <TextBlock Text="用户管理" FontSize="10" FontWeight="Bold" Margin="0,4,0,0" HorizontalAlignment="Center" />
+                </StackPanel>
+            </Button>
+            <Button x:Name="RnIdentifyBtn" HorizontalAlignment="Left" Height="60" Width="60" Margin="360,0,0,0" Background="{x:Null}" Click="RnIdentifyBtn_Click">
+                <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                    <Image Name="RnIdentifyBtn_Image"  Source="/FromImage/运行.png" Width="32" Height="32" />
+                    <TextBlock Name="RnIdentifyBtn_Text" Text="开始运行" FontSize="10" FontWeight="Bold" Margin="0,5,0,0" HorizontalAlignment="Center" />
+                </StackPanel>
+            </Button>
+        </Grid>
+        <Frame x:Name="ShowFrame" Margin="0,60,0,60" NavigationUIVisibility="Hidden"/>
+        <Grid VerticalAlignment="Bottom" Height="40" Margin="0,0,0,5">
+            <Border Grid.Column="0" 
+            Background="#B20092FF" 
+            CornerRadius="8"
+            BorderBrush="Gray"
+            BorderThickness="1"
+            Margin="10,0,10,0" VerticalAlignment="Bottom" Height="40">
+                <StackPanel Orientation="Horizontal">
+                    <Label x:Name="CPUMonitorLab" Content="{Binding CPUMonitor}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Margin="30,8,0,0" Width="80" FontSize="10" FontWeight="Bold"></Label>
+                    <Label x:Name="RamMonitorLab" Content="{Binding RamMonitor}" HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Margin="20,8,0,0" Width="120" FontSize="10" FontWeight="Bold"></Label>
+                </StackPanel>
+            </Border>
+        </Grid>
+    </Grid>
+</Window>

+ 450 - 0
CCDCountWpf/WpfFrom/MainWindow.xaml.cs

@@ -0,0 +1,450 @@
+using CCDCount.DLL;
+using CCDCount.DLL.Tools;
+using CCDCount.MODEL.CameraClass;
+using CCDCount.MODEL.ConfigModel;
+using LogClass;
+using MvCameraControl;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media.Imaging;
+
+namespace CCDCountWpf
+{
+    /// <summary>
+    /// MainWindow.xaml 的交互逻辑
+    /// </summary>
+    public partial class MainWindow : Window
+    {
+        #region 变量与实例
+        Uri ShowUri = null;
+        public ModbusTcpClient modbusTcpClient = new ModbusTcpClient();
+        List<SaveConfigModel> Configs = null;
+        bool IsShow = false;
+        SystemMonitor monitor = new SystemMonitor();
+        #endregion
+
+        #region 窗体事件
+        /// <summary>
+        /// 主窗体构造函数
+        /// </summary>
+        public MainWindow()
+        {
+            InitializeComponent();
+            DataContext = MessageBus.ShowBinding;
+            //if(!modbusTcpClient.Connect("192.168.1.88"))
+            if (!modbusTcpClient.Connect("127.0.0.1"))
+            {
+                FaultLog.RecordErrorMessage("Modbus通讯连接失败");
+            }
+            if (File.Exists(".\\Config\\CCDCountConfig.xml"))
+            {
+                Configs = XmlStorage.DeserializeFromXml<List<SaveConfigModel>>(".\\Config\\CCDCountConfig.xml");
+            }
+            SDKSystem.Initialize();
+            InitCameraIdentify();
+            MainPageBtn_Click(null, null);
+            StartUpdataShowDataThread();
+            InitCamComboboxValue();
+        }
+
+        
+        /// <summary>
+        /// 退出按钮点击事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void ExitBtn_Click(object sender, RoutedEventArgs e)
+        {
+            this.Close();
+        }
+
+        /// <summary>
+        /// 主界面按钮点击事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void MainPageBtn_Click(object sender, RoutedEventArgs e)
+        {
+            ShowUri = new Uri("WpfPage\\MainPage.xaml", UriKind.Relative);
+            ShowFrame.Navigate(ShowUri);
+        }
+
+        /// <summary>
+        /// 开始运行按钮点击事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void RnIdentifyBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if(RnIdentifyBtn_Text.Text == "开始运行")
+            {
+                RunCameraIdentify();
+                RnIdentifyBtn_Image.Source = new BitmapImage(new Uri("/FromImage/暂停.png", UriKind.Relative));
+                RnIdentifyBtn_Text.Text = "停止运行";
+            }
+            else if(RnIdentifyBtn_Text.Text == "停止运行")
+            {
+                StopCameraIdentify();
+                RnIdentifyBtn_Image.Source = new BitmapImage(new Uri("/FromImage/运行.png", UriKind.Relative));
+                RnIdentifyBtn_Text.Text = "开始运行";
+            }
+        }
+
+        private void SettingBtn_Click(object sender, RoutedEventArgs e)
+        {
+            ShowUri = new Uri("WpfPage\\SettingPage.xaml", UriKind.Relative);
+            ShowFrame.Navigate(ShowUri);
+        }
+
+        private void ErrorMessageShowBtn_Click(object sender, RoutedEventArgs e)
+        {
+            ShowUri = new Uri("WpfPage\\MessagePage.xaml", UriKind.Relative);
+            ShowFrame.Navigate(ShowUri);
+        }
+        private void PlcSettingBtn_Click(object sender, RoutedEventArgs e)
+        {
+            ShowUri = new Uri("WpfPage\\PlcSettingPage.xaml", UriKind.Relative);
+            ShowFrame.Navigate(ShowUri);
+        }
+        private void UserMessageBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (MessageBus.NowLoginUserMessage != null)
+            {
+                if (!MessageBus.NowLoginUserMessage.IsAdmin)
+                {
+                    MessageBox.Show("权限不足");
+                }
+                else
+                {
+                    ShowUri = new Uri("WpfPage\\UserManagementPage.xaml", UriKind.Relative);
+                    ShowFrame.Navigate(ShowUri);
+                }
+            }
+            else
+            {
+                MessageBox.Show("请先登录");
+            }
+        }
+        /// <summary>
+        /// 窗体关闭事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
+        {
+            SDKSystem.Finalize();
+            if (MessageBus.MainThreadS.Count != 0)
+            {
+                foreach (var item in MessageBus.MainThreadS)
+                {
+                    item.DisposeCamera();
+                }
+            }
+            Environment.Exit(0);
+        }
+        #endregion
+
+        #region 私有方法
+        private void InitCameraIdentify()
+        {
+            if (Configs.Count == 0)
+            {
+                MessageBox.Show("尚未添加相机,请前往配置页面配置相机");
+                return;
+            }
+            if (MessageBus.MainThreadS.Count != 0)
+            {
+                foreach (var item in MessageBus.MainThreadS)
+                {
+                    item.StopMianThread();
+                }
+            }
+            MessageBus.MainThreadS = new List<MainThreadClass>();
+            for (int i = 0; i < Configs.Count; i++)
+            {
+                MessageBus.MainThreadS.Add(new MainThreadClass(Configs[i].ShuLiConfigClass, Configs[i].CameraConfig));
+
+                MessageBus.MainThreadS[i].SetModbusClient(modbusTcpClient);
+                MessageBus.MainThreadS[i].LoadCamera();
+            }
+        }
+
+        /// <summary>
+        /// 启动相机识别
+        /// </summary>
+        private void RunCameraIdentify()
+        {
+            for (int i = 0; i < MessageBus.MainThreadS.Count; i++)
+            {
+                if(MessageBus.MainThreadS[i].CameraConfigIsChange)
+                {
+                    MessageBus.MainThreadS[i].ReLoadCameraConfig();
+                }
+                //启动单相机实例的全部线程
+                if (!MessageBus.MainThreadS[i].StartMianThread())
+                {
+                    FaultLog.RecordErrorMessage(MessageBus.MainThreadS[i].cameraConfig.DeviceName + "_" + MessageBus.MainThreadS[i].cameraConfig.CameraSNNum + "启动失败");
+                    //LOG.error(MessageBus.MainThreadS[i].cameraConfig.DeviceName + "_" + MessageBus.MainThreadS[i].cameraConfig.CameraSNNum + "启动失败");
+                    MessageBox.Show(MessageBus.MainThreadS[i].cameraConfig.DeviceName + "_" + MessageBus.MainThreadS[i].cameraConfig.CameraSNNum + "启动失败");
+                    continue;
+                }
+            }
+            MessageBus.NowLoadCammeraSN = MessageBus.MainThreadS[0].cameraConfig.CameraSNNum;
+            MessageBus.SeetingNowLoadInMaThreadsIndex = 0;
+            MessageBus.NowLoadCameraIndex = 0;
+        }
+
+        /// <summary>
+        /// 启动相机识别
+        /// </summary>
+        private void StopCameraIdentify()
+        {
+            for (int i = 0; i < MessageBus.MainThreadS.Count; i++)
+            {
+                //启动单相机实例的全部线程
+                if (!MessageBus.MainThreadS[i].StopMianThread())
+                {
+                    FaultLog.RecordErrorMessage(MessageBus.MainThreadS[i].cameraConfig.DeviceName + "_" + MessageBus.MainThreadS[i].cameraConfig.CameraSNNum + "关闭失败");
+                    MessageBox.Show(MessageBus.MainThreadS[i].cameraConfig.DeviceName + "_" + MessageBus.MainThreadS[i].cameraConfig.CameraSNNum + "关闭失败");
+                    continue;
+                }
+            }
+        }
+        /// <summary>
+        ///  启动更新显示数据线程
+        /// </summary>
+        private  void StartUpdataShowDataThread()
+        {
+            IsShow = true;
+            Bitmap image1 = null;
+            Bitmap image2 = null;
+            Bitmap image3 = null;
+            Bitmap image4 = null;
+            const int targetMsPerFrame = 100; // 20FPS=50ms
+            Stopwatch renderSW = new Stopwatch();
+            Task.Run(async () =>
+            {
+                while (IsShow)
+                {
+                    renderSW.Restart();
+                    await Task.Run(() =>
+                    {
+                        UpdataShuLiShowData();
+                        UpdateMonitorMessage();
+                        UpdateFaultLogMessage();
+                    });
+
+                    if (MessageBus.MainThreadS.Count == 0)
+                    {
+                        LOG.log(string.Format("{0}:当前未加载识别流程", "IdentifyCameraForm-StartShowImageThread"));
+                        Thread.Sleep(100);
+                        continue;
+                    }
+                    if(MessageBus.MainThreadS.Count>=1)
+                    {
+                        if (MessageBus.MainThreadS[0].HistoryActiveNum > 0)
+                        {
+                            MessageBus.MainThreadS[0].GetShowImage(2000, out image1);
+                        }
+                        else
+                        {
+                            MessageBus.MainThreadS[0].GetNullShowImage(4096, 2000, out image1);
+                        }
+                        if (image1 == null)
+                        {
+                            LOG.log(string.Format("{0}:相机一获取图片为空", "IdentifyCameraForm-StartShowImageThread"));
+                            continue;
+                        }
+                    }
+
+                    if (MessageBus.MainThreadS.Count >= 2)
+                    {
+                        if (MessageBus.MainThreadS[1].HistoryActiveNum > 0)
+                        {
+                            MessageBus.MainThreadS[1].GetShowImage(2000, out image2);
+                        }
+                        else
+                        {
+                            MessageBus.MainThreadS[1].GetNullShowImage(4096, 2000, out image2);
+                        }
+                        if (image2 == null)
+                        {
+                            LOG.log(string.Format("{0}:相机二获取图片为空", "IdentifyCameraForm-StartShowImageThread"));
+                            continue;
+                        }
+                    }
+
+                    if (MessageBus.MainThreadS.Count >= 3)
+                    {
+                        if (MessageBus.MainThreadS[2].HistoryActiveNum > 0)
+                        {
+                            MessageBus.MainThreadS[2].GetShowImage(2000, out image3);
+                        }
+                        else
+                        {
+                            MessageBus.MainThreadS[2].GetNullShowImage(4096, 2000, out image3);
+                        }
+                        if (image3 == null)
+                        {
+                            LOG.log(string.Format("{0}:相机三获取图片为空", "IdentifyCameraForm-StartShowImageThread"));
+                            continue;
+                        }
+                    }
+
+                    await Application.Current.Dispatcher.InvokeAsync(() =>
+                    {
+                        BitmapImage thumbnailImage1 = null;
+                        BitmapImage thumbnailImage2 = null;
+                        BitmapImage thumbnailImage3 = null;
+                        BitmapImage thumbnailImage4 = null;
+                        if (image1 != null)
+                        {
+                            thumbnailImage1 = ConvertToBitmapImage(image1);
+                            MessageBus.ShowBinding.ThumbnailImage1 = thumbnailImage1;
+                        }
+                        if (image2 != null)
+                        {
+                            thumbnailImage2 = ConvertToBitmapImage(image2);
+                            MessageBus.ShowBinding.ThumbnailImage2 = thumbnailImage2;
+                        }
+                        if (image3 != null)
+                        {
+                            thumbnailImage3 = ConvertToBitmapImage(image3);
+                            MessageBus.ShowBinding.ThumbnailImage3 = thumbnailImage3;
+                        }
+                        if (image4 != null)
+                        {
+                            thumbnailImage4 = ConvertToBitmapImage(image4);
+                            MessageBus.ShowBinding.ThumbnailImage4 = thumbnailImage4;
+                        }
+                        if (MessageBus.NowLoadCameraIndex == 0)
+                        {
+                            MessageBus.ShowBinding.BitmapImage = thumbnailImage1;
+                        }
+                        else if (MessageBus.NowLoadCameraIndex == 2)
+                        {
+                            MessageBus.ShowBinding.BitmapImage = thumbnailImage2;
+                        }
+                        else if (MessageBus.NowLoadCameraIndex == 3)
+                        {
+                            MessageBus.ShowBinding.BitmapImage = thumbnailImage3;
+                        }
+                        else if (MessageBus.NowLoadCameraIndex == 4)
+                        {
+                            MessageBus.ShowBinding.BitmapImage = thumbnailImage4;
+                        }
+                    });
+                    //进行精准20帧控制
+                    int elapsed = (int)renderSW.ElapsedMilliseconds;
+                    //Console.WriteLine(elapsed);
+                    if (elapsed < targetMsPerFrame)
+                    {
+                        Thread.Sleep(targetMsPerFrame - elapsed);
+                    }
+                    //Thread.Sleep(50);
+                }
+            });
+        }
+
+        /// <summary>
+        ///  停止更新显示数据线程
+        /// </summary>
+        private void StopUpdataShowDataThread()
+        {
+            IsShow = false;
+        }
+
+
+        /// <summary>
+        /// 更新数粒显示数据
+        /// </summary>
+        private void UpdataShuLiShowData()
+        {
+            if (MessageBus.MainThreadS.Count == 0) return;
+            if(MessageBus.NowLoadCameraIndex ==  -1) return;
+            if (MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].ShuLiState)
+            {
+                Application.Current.Dispatcher.Invoke(() =>
+                {
+                    MessageBus.ShowBinding.CameraStaticColor = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].CameraRunStatic == true
+                        ? System.Windows.Media.Brushes.Green : System.Windows.Media.Brushes.Red;
+                    MessageBus.ShowBinding.CamRunStatic = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].CameraRunStatic == true 
+                        ? "运行中" : "未运行";
+                });
+            }
+            else
+            {
+                Application.Current.Dispatcher.Invoke(() =>
+                {
+
+                    MessageBus.ShowBinding.CameraStaticColor = System.Windows.Media.Brushes.Yellow;
+                    MessageBus.ShowBinding.CamRunStatic = "视野遮挡";
+                });
+            }
+            MessageBus.ShowBinding.AllActiveNum = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].HistoryActiveNum.ToString();
+            MessageBus.ShowBinding.AllOkNum = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].OkHistoryNum.ToString();
+            MessageBus.ShowBinding.AllNgNum = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].NgHistoryNum.ToString();
+            MessageBus.ShowBinding.ShuLiSpeed = MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].GetOneSecondActiveNum().ToString();
+        }
+
+        /// <summary>
+        /// 更新监控信息
+        /// </summary>
+        private void UpdateMonitorMessage()
+        {
+            MessageBus.ShowBinding.RamMonitor = monitor.GetAvailableMemory() > 1024 ? $"可用内存: {monitor.GetAvailableMemory() / 1024:0.00}GB" : $"可用内存: {monitor.GetAvailableMemory()}MB";
+            MessageBus.ShowBinding.CPUMonitor = $"CPU: {monitor.GetCpuUsage():0.00}%";
+        }
+
+        /// <summary>
+        /// 更新故障日志信息
+        /// </summary>
+        private void UpdateFaultLogMessage()
+        {
+            MessageBus.ShowBinding.ErrMessageShowList = FaultLog.GetAllErrMessage();
+        }
+
+        // Bitmap 转 BitmapImage 的辅助方法
+        private BitmapImage ConvertToBitmapImage(Bitmap bitmap)
+        {
+            using (MemoryStream memory = new MemoryStream())
+            {
+                bitmap.Save(memory, System.Drawing.Imaging.ImageFormat.Png);
+                memory.Position = 0;
+                var bitmapImage = new BitmapImage();
+                bitmapImage.BeginInit();
+                bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
+                bitmapImage.StreamSource = memory;
+                bitmapImage.EndInit();
+                return bitmapImage;
+            }
+        }
+
+        private void InitCamComboboxValue()
+        {
+            List<CameraInfoClass> CameraInfoList = new List<CameraInfoClass>();
+            MessageBus.CameraClass.GetCameraList(out CameraInfoList);
+            if (CameraInfoList.Count > 0)
+            {
+                MessageBus.ShowBinding.CameraItems.Clear();
+                MessageBus.ShowBinding.CameraItems.Add(new CameraCoboxItem() { Name = "请选择相机", SNValue = "" });
+                foreach (var item in CameraInfoList)
+                {
+                    MessageBus.ShowBinding.CameraItems.Add(new CameraCoboxItem()
+                    {
+                        Name = item.DeviceName + "_" + item.DeviceSN,
+                        SNValue = item.DeviceSN
+                    });
+                }
+            }
+        }
+        #endregion
+    }
+}

+ 18 - 0
CCDCountWpf/WpfFrom/SplashWindow.xaml

@@ -0,0 +1,18 @@
+<Window x:Class="CCDCountWpf.SplashWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:CCDCountWpf"
+        mc:Ignorable="d"
+        Title="SplashWindow" Height="450" Width="800" 
+        WindowStyle="None" AllowsTransparency="True"
+        Background="Transparent" WindowStartupLocation="CenterScreen" Icon="/FromImage/mmexport1752891278116.jpg">
+    <Grid Background="White">
+        <TextBlock Text="翰林航宇视觉数粒系统" HorizontalAlignment="Center" 
+                           Foreground="#FF0072BF" FontSize="40" VerticalAlignment="Top" Cursor="Arrow" Margin="0,20,0,0"/>
+        <Image Source="/FromImage/mmexport1752891278116.jpg" Stretch="Fill" Width="200" Height="200" Cursor="Arrow"/>
+        <TextBlock Text="程序启动中" HorizontalAlignment="Right" Margin="0,0,60,20" 
+                           Foreground="#FF0072BF" FontSize="40" VerticalAlignment="Bottom" Cursor="Arrow"/>
+    </Grid>
+</Window>

+ 27 - 0
CCDCountWpf/WpfFrom/SplashWindow.xaml.cs

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

+ 62 - 0
CCDCountWpf/WpfFrom/UserLoginWindow.xaml

@@ -0,0 +1,62 @@
+<Window x:Class="CCDCountWpf.UserLoginWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:CCDCountWpf"
+        mc:Ignorable="d"
+        Title="UserLoginWindow" Height="300" Width="450"
+        WindowStyle="None" AllowsTransparency="True"
+        WindowStartupLocation="CenterScreen" Icon="/FromImage/mmexport1752891278116.jpg" KeyDown="Window_KeyDown">
+    <Grid Background="#B2E0E0E0">
+        <Grid VerticalAlignment="Top" Height="50" Background="#B20092FF">
+            <Border BorderBrush="Black" BorderThickness="1"/>
+            <Label Content="用户登录" Foreground="Black" FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
+        </Grid>
+        <Border  Background="#B20092FF" 
+                    CornerRadius="8"
+                    BorderBrush="Gray"
+                    BorderThickness="1"
+                    Margin="80,120,80,0" Height="155" VerticalAlignment="Top">
+            <StackPanel Orientation="Vertical">
+                <StackPanel Orientation="Horizontal" Height="95">
+                    <StackPanel Orientation="Vertical" Margin="30,0,0,0">
+                        <Label  Content="用户名:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                        <Label  Content="密码:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                    </StackPanel>
+                    <StackPanel Orientation="Vertical">
+                        <TextBox x:Name="UserNameTbx" HorizontalAlignment="Left" Margin="0,15,0,0"  Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"/>
+                        <PasswordBox x:Name="UserPassTbx"  HorizontalAlignment="Left" Margin="0,17,0,0" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" Background="{x:Null}"  />
+                    </StackPanel>
+                </StackPanel>
+                <StackPanel Orientation="Horizontal">
+                    <Button x:Name="UserLoginBtn" Content="登录" BorderThickness="1" HorizontalAlignment="Left" Margin="50,10,10,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserLoginBtn_Click" Cursor="Hand">
+                        <Button.Template>
+                            <ControlTemplate TargetType="Button">
+                                <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                                </Border>
+                            </ControlTemplate>
+                        </Button.Template>
+                    </Button>
+                    <Button x:Name="UserCancelBtn" Content="取消" BorderThickness="1" HorizontalAlignment="Left" Margin="10,10,10,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="UserCancelBtn_Click" Cursor="Hand">
+                        <Button.Template>
+                            <ControlTemplate TargetType="Button">
+                                <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                                </Border>
+                            </ControlTemplate>
+                        </Button.Template>
+                    </Button>
+                </StackPanel>
+            </StackPanel>
+            <!-- 卡片内容 -->
+        </Border>
+    </Grid>
+</Window>

+ 62 - 0
CCDCountWpf/WpfFrom/UserLoginWindow.xaml.cs

@@ -0,0 +1,62 @@
+using CCDCount.DLL;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf
+{
+    /// <summary>
+    /// UserLoginWindow.xaml 的交互逻辑
+    /// </summary>
+    public partial class UserLoginWindow : Window
+    {
+        public UserLoginWindow()
+        {
+            InitializeComponent();
+        }
+
+        private void UserLoginBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if(!MessageBus.UserMessageClass.CheckUserLogin(UserNameTbx.Text, UserPassTbx.Password))
+            {
+                MessageBox.Show("用户名或密码错误!");
+                return;
+            }
+            MessageBus.NowLoginUserMessage = MessageBus.UserMessageClass.GetUserMessageForName(UserNameTbx.Text)[0];
+            FaultLog.SetUserID(MessageBus.NowLoginUserMessage.Id);
+            SplashWindow splash = new SplashWindow();
+            splash.Show();
+            this.Close();
+
+            MainWindow mainWindow = new MainWindow();
+            mainWindow.Show();
+            splash.Close();
+        }
+
+        private void UserCancelBtn_Click(object sender, RoutedEventArgs e)
+        {
+            this.Close();
+            Environment.Exit(0);
+        }
+
+        private void Window_KeyDown(object sender, KeyEventArgs e)
+        {
+            if (e.Key == Key.Enter)
+            {
+                // 触发目标按钮的点击事件
+                UserLoginBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
+                e.Handled = true; // 标记事件已处理
+            }
+        }
+    }
+}

+ 93 - 0
CCDCountWpf/WpfPage/MainPage.xaml

@@ -0,0 +1,93 @@
+<Page x:Class="CCDCountWpf.WpfPage.MainPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:CCDCountWpf.WpfPage"
+      mc:Ignorable="d"
+      Title="MainPage" Height="503" Width="876" Loaded="Page_Loaded">
+
+    <Grid>
+        <Grid Margin="0,0,0,187" SizeChanged="Grid_SizeChanged">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*"/>
+                <ColumnDefinition Width="*"/>
+            </Grid.ColumnDefinitions>
+            <Border Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="2,2,2,2">
+                <Image x:Name="ShowBox"  Source="{Binding BitmapImage}" Margin="0,0,0,0"/>
+            </Border>
+            <Border Grid.Column="1" BorderBrush="Black" BorderThickness="1" Margin="2,2,2,2">
+                <StackPanel  Orientation="Vertical">
+                    <Image x:Name="MiniShowImageBox1"  Source="{Binding ThumbnailImage1}" Margin="3,5,3,5" MouseDown="MiniShowImageBox1_MouseDown" />
+                    <Image x:Name="MiniShowImageBox2"  Source="{Binding ThumbnailImage2}" Margin="3,5,3,5" MouseDown="MiniShowImageBox2_MouseDown" />
+                    <Image x:Name="MiniShowImageBox3"  Source="{Binding ThumbnailImage3}" Margin="3,5,3,5" MouseDown="MiniShowImageBox3_MouseDown"/>
+                    <Image x:Name="MiniShowImageBox4"  Source="{Binding ThumbnailImage4}" Margin="3,5,3,5" MouseDown="MiniShowImageBox4_MouseDown"/>
+                </StackPanel>
+            </Border>
+        </Grid>
+        
+        <Grid Margin="0,0,0,10" Height="170" VerticalAlignment="Bottom">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*"/>
+                <ColumnDefinition Width="*"/>
+            </Grid.ColumnDefinitions>
+
+            <Border Grid.Column="0" 
+                    Background="#B20092FF" 
+                    CornerRadius="8"
+                    BorderBrush="Gray"
+                    BorderThickness="1"
+                    Margin="15,10,15,0" Height="155" VerticalAlignment="Top">
+
+                <StackPanel Orientation="Horizontal">
+                    <StackPanel Orientation="Vertical">
+                        <Label  Content="当前总粒数:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                        <Label  Content="当前合格数:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                        <Label  Content="当前不合格数:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                    </StackPanel>
+                    <StackPanel Orientation="Vertical">
+                        <TextBox x:Name="AllActiveNumTbx" Text="{Binding AllActiveNum}" HorizontalAlignment="Left" Margin="0,15,0,0"  TextWrapping="Wrap" Width="120" FontWeight="Bold" FontSize="20" IsReadOnly="True" Background="{x:Null}"/>
+                        <TextBox x:Name="AllOkNumTbx" Text="{Binding AllOkNum}" HorizontalAlignment="Left" Margin="0,17,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" IsReadOnly="True" Background="{x:Null}"/>
+                        <TextBox x:Name="AllNgNumTbx" Text="{Binding AllNgNum}" HorizontalAlignment="Left" Margin="0,17,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" FontWeight="Bold" FontSize="20" IsReadOnly="True" Background="{x:Null}"/>
+                    </StackPanel>
+                    <StackPanel Orientation="Vertical">
+                        <Label x:Name="CamRunStaticLab" Content="{Binding CamRunStatic}" HorizontalAlignment="Right" Margin="10,5,10,0" VerticalAlignment="Top" Background="{x:Null}" FontSize="25" Foreground="{Binding CameraStaticColor}" FontWeight="Bold" />
+                        <Button x:Name="DataClear" Content="清零" BorderThickness="1" HorizontalAlignment="Left" Margin="10,50,10,0" VerticalAlignment="Top" Width="80" Height="40" Background="#B20123FF" FontWeight="Bold" FontSize="20" Foreground="White" Click="DataClear_Click" Cursor="Hand">
+                            <Button.Template>
+                                <ControlTemplate TargetType="Button">
+                                    <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                                    </Border>
+                                </ControlTemplate>
+                            </Button.Template>
+                        </Button>
+                    </StackPanel>
+                </StackPanel>
+                <!-- 卡片内容 -->
+            </Border>
+
+            <Border Grid.Column="1" 
+                    Background="#B20092FF" 
+                    CornerRadius="8"
+                    BorderBrush="Gray"
+                    BorderThickness="1"
+                    Margin="15,10,15,0" Height="60" VerticalAlignment="Top">
+                <StackPanel Orientation="Horizontal">
+                    <StackPanel Orientation="Vertical">
+                        <Label  Content="计数速度:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontWeight="Bold" FontSize="20"/>
+                    </StackPanel>
+                    <StackPanel Orientation="Vertical" Margin="40,0,0,0" >
+                        <TextBox x:Name="ShuLiSpeedTbx" Text="{Binding ShuLiSpeed}" HorizontalAlignment="Left" Margin="0,15,0,0"  TextWrapping="Wrap" Width="120" FontWeight="Bold" FontSize="20" IsReadOnly="True" Background="{x:Null}"/>
+                    </StackPanel>
+                    <StackPanel Orientation="Vertical" Margin="10,0,0,0" >
+                        <Label Content="粒/秒" FontWeight="Bold" FontSize="20" Margin="0,10,0,0" />
+                    </StackPanel>
+                </StackPanel>
+            </Border>
+        </Grid>
+        
+    </Grid>
+</Page>

+ 82 - 0
CCDCountWpf/WpfPage/MainPage.xaml.cs

@@ -0,0 +1,82 @@
+
+using LogClass;
+using MvCameraControl;
+using System;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Interop;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using static System.Net.Mime.MediaTypeNames;
+
+namespace CCDCountWpf.WpfPage
+{
+    /// <summary>
+    /// MainPage.xaml 的交互逻辑
+    /// </summary>
+    public partial class MainPage : Page
+    {
+        #region 变量与实例
+        #endregion
+        public MainPage()
+        {
+            InitializeComponent();
+            DataContext  =  MessageBus.ShowBinding;
+        }
+
+        private void DataClear_Click(object sender, RoutedEventArgs e)
+        {
+            if(MessageBus.MainThreadS.Count<MessageBus.NowLoadCameraIndex+1)
+                return;
+            MessageBus.MainThreadS[MessageBus.NowLoadCameraIndex].ClearHistoryActive();
+        }
+
+        private void Page_Loaded(object sender, RoutedEventArgs e)
+        {
+            this.Width = double.NaN; // 等效于 Auto
+            this.Height = double.NaN;
+        }
+
+        private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
+        {
+            if (sender is Grid grid)
+            {
+                double columnWidth = grid.ActualHeight / 2; // 高度/2作为列宽
+                grid.ColumnDefinitions[1].Width = new GridLength(columnWidth);
+                MiniShowImageBox1.Height = columnWidth / 2 - 10;
+                MiniShowImageBox2.Height = columnWidth / 2 - 10;
+                MiniShowImageBox3.Height = columnWidth / 2 - 10;
+                MiniShowImageBox4.Height = columnWidth / 2 - 10;
+            }
+        }
+
+        private void MiniShowImageBox2_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            if(MessageBus.MainThreadS.Count < 2) return;
+            MessageBus.NowLoadCameraIndex = 1;
+        }
+
+        private void MiniShowImageBox1_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            if (MessageBus.MainThreadS.Count < 1) return;
+            MessageBus.NowLoadCameraIndex = 0;
+        }
+
+        private void MiniShowImageBox3_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            if (MessageBus.MainThreadS.Count < 3) return;
+            MessageBus.NowLoadCameraIndex = 2;
+        }
+
+        private void MiniShowImageBox4_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
+        {
+            if (MessageBus.MainThreadS.Count < 4) return;
+            MessageBus.NowLoadCameraIndex = 3;
+        }
+    }
+}

+ 23 - 0
CCDCountWpf/WpfPage/MessagePage.xaml

@@ -0,0 +1,23 @@
+<Page x:Class="CCDCountWpf.WpfPage.MessagePage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:CCDCountWpf.WpfPage"
+      mc:Ignorable="d" 
+      d:DesignHeight="450" d:DesignWidth="800"
+      Title="MessagePage">
+
+    <Grid>
+        <DataGrid ItemsSource="{Binding ErrMessageShowList}" AutoGenerateColumns="False">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="编号" Binding="{Binding Number}" />
+                <DataGridTextColumn Header="类别" Binding="{Binding Category}" />
+                <DataGridTextColumn Header="类型" Binding="{Binding MessageType}" />
+                <DataGridTextColumn Header="消息文本" Binding="{Binding Message}" />
+                <DataGridTextColumn Header="时间" Binding="{Binding DateTime}" />
+                <DataGridTextColumn Header="用户ID" Binding="{Binding UserID}" />
+            </DataGrid.Columns>
+        </DataGrid>
+    </Grid>
+</Page>

+ 29 - 0
CCDCountWpf/WpfPage/MessagePage.xaml.cs

@@ -0,0 +1,29 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf.WpfPage
+{
+    /// <summary>
+    /// MessagePage.xaml 的交互逻辑
+    /// </summary>
+    public partial class MessagePage : Page
+    {
+        public MessagePage()
+        {
+            InitializeComponent();
+            DataContext = MessageBus.ShowBinding;
+        }
+    }
+}

+ 14 - 0
CCDCountWpf/WpfPage/PlcSettingPage.xaml

@@ -0,0 +1,14 @@
+<Page x:Class="CCDCountWpf.WpfPage.PlcSettingPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:CCDCountWpf.WpfPage"
+      mc:Ignorable="d" 
+      d:DesignHeight="450" d:DesignWidth="800"
+      Title="PlcSettingPage">
+
+    <Grid>
+        
+    </Grid>
+</Page>

+ 28 - 0
CCDCountWpf/WpfPage/PlcSettingPage.xaml.cs

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

+ 147 - 0
CCDCountWpf/WpfPage/SettingPage.xaml

@@ -0,0 +1,147 @@
+<Page x:Class="CCDCountWpf.WpfPage.SettingPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:CCDCountWpf.WpfPage"
+      mc:Ignorable="d" 
+      d:DesignHeight="550" d:DesignWidth="800"
+      Title="SettingPage" Loaded="Page_Loaded">
+
+    <Grid>
+        <Grid Margin="0,0,0,0">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="*"/>
+                <ColumnDefinition Width="330"/>
+            </Grid.ColumnDefinitions>
+            <Border Grid.Column="0" BorderBrush="Black" BorderThickness="1" Margin="2,2,2,2">
+                <Image x:Name="ShowBox"  Source="{Binding BitmapImage}" Margin="0,0,0,0"/>
+            </Border>
+
+            <Grid Grid.Column="1"  Margin="2,2,2,2">
+                <Border BorderBrush="Black" BorderThickness="1"/>
+                <Grid  x:Name="HeardGrid" Height="40" VerticalAlignment="Top">
+                    <Border BorderBrush="Black" BorderThickness="1"/>
+                    <Button x:Name="Cam1Btn" HorizontalAlignment="Left" Width="60" Background="{x:Null}" Click="Cam1Btn_Click">
+                        <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                            <TextBlock Text="相机一" FontSize="10" FontWeight="Bold" Margin="0,0,0,0" HorizontalAlignment="Center" />
+                        </StackPanel>
+                    </Button>
+                    <Button x:Name="Cam2Btn" HorizontalAlignment="Left" Width="60" Margin="60,0,0,0" Background="{x:Null}" Click="Cam2Btn_Click">
+                        <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                            <TextBlock Text="相机二" FontSize="10" FontWeight="Bold" Margin="0,0,0,0" HorizontalAlignment="Center" />
+                        </StackPanel>
+                    </Button>
+                    <Button x:Name="Cam3Btn" HorizontalAlignment="Left" Width="60" Margin="120,0,0,0" Background="{x:Null}">
+                        <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                            <TextBlock Text="相机三" FontSize="10" FontWeight="Bold" Margin="0,0,0,0" HorizontalAlignment="Center" />
+                        </StackPanel>
+                    </Button>
+                    <Button x:Name="Cam4Btn" HorizontalAlignment="Left" Width="60" Margin="180,0,0,0" Background="{x:Null}">
+                        <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                            <TextBlock Text="相机四" FontSize="10" FontWeight="Bold" Margin="0,0,0,0" HorizontalAlignment="Center" />
+                        </StackPanel>
+                    </Button>
+                    <ComboBox x:Name="CamNumCoBox"  HorizontalAlignment="Right" Margin="240,0,0,0" Width="90" Background="{x:Null}" FontSize="12" HorizontalContentAlignment="Center" Padding="6,12,5,3" SelectionChanged="CamNumCoBox_SelectionChanged"/>
+                </Grid>
+                <Grid x:Name="SettingGrid" Margin="0,40,0,60">
+                    <Grid x:Name ="BtnList" Height="40" VerticalAlignment="Top">
+                        <Button x:Name="CameraSettingBtn" Content="相机参数设置" HorizontalAlignment="Left" Margin="0,0,0,0" Width="165" Background="{x:Null}" Click="CameraSettingBtn_Click"/>
+                        <Button x:Name="ShuLiSettingBtn" Content="数粒参数设置" HorizontalAlignment="Left" Margin="165,0,0,0" Width="165" Background="{x:Null}" Click="ShuLiSettingBtn_Click"/>
+                    </Grid>
+                    <Grid x:Name="CameraSettingGrid" Margin="0,40,0,0" Visibility="Collapsed">
+                        <Label x:Name="CameraSelectLab"  Content="选择相机:" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0" FontSize="15" Height="30" Width="85"/>
+                        <ComboBox x:Name="CamSelectConBox" ItemsSource="{Binding CameraItems}" DisplayMemberPath="Name" SelectedValuePath="SNValue" SelectedValue="{Binding SelectedCameraSN}" Background="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="105,10,0,0" Height="30" Width="180" FontSize="12" HorizontalContentAlignment="Center" Padding="6,6,5,3" SelectionChanged="CamSelectConBox_SelectionChanged" />
+                        <Button x:Name="CamListFlushBtn" HorizontalAlignment="Right" VerticalAlignment="Top" Width="30" Height="30" Margin="0,10,5,0" Background="#FF1709AF" Click="CamListFlushBtn_Click">
+                            <Button.Template>
+                                <ControlTemplate TargetType="Button">
+                                    <Border CornerRadius="5" 
+                                            Background="{TemplateBinding Background}"
+                                            BorderBrush="{TemplateBinding BorderBrush}"
+                                            BorderThickness="{TemplateBinding BorderThickness}">
+                                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
+                                    </Border>
+                                </ControlTemplate>
+                            </Button.Template>
+                            <StackPanel Orientation="Vertical" HorizontalAlignment="Center">
+                                <Image  Source="/FromImage/刷新.png" Width="25" Height="25" />
+                            </StackPanel>
+                        </Button>
+                        <StackPanel Orientation="Horizontal" Margin="0,50,0,0">
+                            <StackPanel x:Name="CameraParameLab" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0">
+                                <Label x:Name="ExposureTimeLab" Content="曝光:" Width="85" Height="30" FontSize="15" />
+                                <Label x:Name="AcquistionLineRateLab" Content="行频:" Width="85" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <Label x:Name="ImageWidthLab" Content="图像宽:" Width="85" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <Label x:Name="ImageHeightLab" Content="图像高:" Width="85" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <Label x:Name="CamUserNameLab" Content="用户设定名:" Width="85" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <Label x:Name="CamOffsetXLab" Content="视野偏移:" Width="85" Height="30" FontSize="15" Margin="0,10,0,0" />
+                            </StackPanel>
+                            <StackPanel x:Name="CameraParameTbx" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0">
+                                <TextBox x:Name="ExposureTimeTbx" Width="100" Text="{Binding ExposureTimeValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="30" FontSize="15" />
+                                <TextBox x:Name="AcquistionLineRateTbx" Text="{Binding AcquistionLineRate,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <TextBox x:Name="ImageWidthTbx" Text="{Binding ImageWidth,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <TextBox x:Name="ImageHeightTbx" Text="{Binding ImageHeight,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <TextBox x:Name="CamUserNameTbx" Text="{Binding CamUserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <TextBox x:Name="CamOffsetXTbx" Text="{Binding CamOffsetX,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="100" Height="30" FontSize="15" Margin="0,10,0,0" />
+                            </StackPanel>
+                        </StackPanel>
+                    </Grid>
+                    <Grid x:Name="ShuLiSettingGrid" Margin="0,40,0,0" Visibility="Visible">
+                        <StackPanel Orientation="Horizontal" Height="130" VerticalAlignment="Top">
+                            <StackPanel Orientation="Vertical" Margin="10,10,0,0">
+                                <Label x:Name="RegionThresholdLab" Content="预处理阈值:" Width="90" Height="30" FontSize="15" />
+                                <Label x:Name="ChannelLab" Content="阀门通道数:" Width="90" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <Label x:Name="NoiseFilterLab" Content="噪点过滤:" Width="90" Height="30" FontSize="15" Margin="0,10,0,0" />
+                            </StackPanel>
+                            <StackPanel Orientation="Vertical" Margin="10,10,0,0">
+                                <TextBox x:Name="RegionThresholdTbx" Width="100" Text="{Binding RegionThreshold,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="30" FontSize="15" />
+                                <TextBox x:Name="ChannelTbx" Width="100" Text="{Binding Channel,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="30" FontSize="15" Margin="0,10,0,0" />
+                                <TextBox x:Name="NoiseFilterTbx" Width="100" Text="{Binding NoiseFilter,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="30" FontSize="15" Margin="0,10,0,0" />
+                            </StackPanel>
+                        </StackPanel>
+                        <Label Content="合格检测类型" Margin="10,140,0,0" FontSize="15"/>
+                        <RadioButton x:Name="CheckModel1RadBtn" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,175,0,0" Content="不检测" FontSize="15" Checked="CheckModel1RadBtn_Checked" />
+                        <RadioButton x:Name="CheckModel2RadBtn" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,205,0,0" Content="通过宽高检测" FontSize="15" Checked="CheckModel2RadBtn_Checked" />
+                        <RadioButton x:Name="CheckModel3RadBtn" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,235,0,0" Content="通过面积" FontSize="15" Checked="CheckModel3RadBtn_Checked" />
+                        <RadioButton x:Name="CheckModel4RadBtn" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="40,265,0,0" Content="通过宽高面积检测" FontSize="15" Checked="CheckModel4RadBtn_Checked" />
+                        <StackPanel Orientation="Vertical" Height="100" VerticalAlignment="Top" Margin="0,290,0,0">
+                            <StackPanel x:Name="WHParaPanel" Orientation="Horizontal">
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="120" Content="合格粒宽范围:" FontSize="15"/>
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="120" Content="合格粒高范围:" FontSize="15"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <TextBox x:Name="MIN_OBJECT_WIDTH_TBX" Text="{Binding MIN_OBJECT_WIDTH,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,4,0,0" Width="70"/>
+                                    <TextBox x:Name="MIN_OBJECT_HEIGHT_TBX" Text="{Binding MIN_OBJECT_HEIGHT,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,9,0,0" Width="70"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="15" Content="-" FontSize="15"/>
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="15" Content="-" FontSize="15"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <TextBox x:Name="MAX_OBJECT_WIDTH_TBX" Text="{Binding MAX_OBJECT_WIDTH,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,4,0,0" Width="70"/>
+                                    <TextBox x:Name="MAX_OBJECT_HEIGHT_TBX" Text="{Binding MAX_OBJECT_HEIGHT,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,9,0,0" Width="70"/>
+                                </StackPanel>
+                            </StackPanel>
+                            <StackPanel x:Name="AreaParaPanel" Orientation="Horizontal">
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="120" Content="合格粒面积范围:" FontSize="15"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <TextBox x:Name="MinArea_TBX" Text="{Binding MinArea,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,4,0,0" Width="70"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <Label HorizontalAlignment="Left" VerticalAlignment="Top" Height="30" Width="15" Content="-" FontSize="15"/>
+                                </StackPanel>
+                                <StackPanel Orientation="Vertical" Margin="10,0,0,0">
+                                    <TextBox x:Name="MaxArea_TBX" Text="{Binding MaxArea,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Height="20" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="15" Margin="0,4,0,0" Width="70"/>
+                                </StackPanel>
+                            </StackPanel>
+                        </StackPanel>
+                    </Grid>
+                </Grid>
+                <Button x:Name="SaveAllConfigBtn" Content="保存全部配置" VerticalAlignment="Bottom" Height="60" Margin="2,0,2,2" FontSize="20" Click="SaveAllConfigBtn_Click"/>
+            </Grid>
+        </Grid>
+    </Grid>
+</Page>

+ 268 - 0
CCDCountWpf/WpfPage/SettingPage.xaml.cs

@@ -0,0 +1,268 @@
+using CCDCount.MODEL.CameraClass;
+using CCDCount.MODEL.ConfigModel;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf.WpfPage
+{
+    /// <summary>
+    /// SettingPage.xaml 的交互逻辑
+    /// </summary>
+    public partial class SettingPage : Page
+    {
+        public SettingPage()
+        {
+            InitializeComponent();
+            DataContext = MessageBus.ShowBinding;
+            Cam1Btn_Click(null, null);
+        }
+
+        private void Page_Loaded(object sender, RoutedEventArgs e)
+        {
+            CamNumCoBox.Items.Add("单相机");
+            CamNumCoBox.Items.Add("双相机");
+            CamNumCoBox.Items.Add("三相机");
+            CamNumCoBox.Items.Add("四相机");
+            CamNumCoBox.SelectedIndex = 0;
+            if (MessageBus.NowSettingLoadMainThread != null)
+            {
+                CamSelectConBox.SelectedValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+                if(MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode == -1)
+                {
+                    CheckModel1RadBtn.IsChecked = true;
+                }
+                else if(MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode == 0)
+                {
+                    CheckModel2RadBtn.IsChecked = true;
+                }
+                else if (MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode == 1)
+                {
+                    CheckModel3RadBtn.IsChecked = true;
+                }
+                else if (MessageBus.NowSettingLoadMainThread.shuLiConfig.PandingCode == 2)
+                {
+                    CheckModel4RadBtn.IsChecked = true;
+                }
+            }
+            else
+            {
+                CamSelectConBox.SelectedValue = "";
+            }
+        }
+
+        private void CamNumCoBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if(CamNumCoBox.SelectedItem.ToString() == "单相机")
+            {
+                Cam1Btn.Visibility = Visibility.Visible;
+                Cam2Btn.Visibility = Visibility.Collapsed;
+                Cam3Btn.Visibility = Visibility.Collapsed;
+                Cam4Btn.Visibility = Visibility.Collapsed;
+                if(!(MessageBus.SeetingNowLoadInMaThreadsIndex>0&&MessageBus.SeetingNowLoadInMaThreadsIndex < 1))
+                {
+                    Cam1Btn_Click(null, null);
+                }
+            }
+            else if(CamNumCoBox.SelectedItem.ToString() == "双相机")
+            {
+                Cam1Btn.Visibility = Visibility.Visible;
+                Cam2Btn.Visibility = Visibility.Visible;
+                Cam3Btn.Visibility = Visibility.Collapsed;
+                Cam4Btn.Visibility = Visibility.Collapsed;
+                if (!(MessageBus.SeetingNowLoadInMaThreadsIndex > 0 && MessageBus.SeetingNowLoadInMaThreadsIndex < 2))
+                {
+                    Cam1Btn_Click(null, null);
+                }
+            }
+            else if(CamNumCoBox.SelectedItem.ToString() == "三相机")
+            {
+                Cam1Btn.Visibility = Visibility.Visible;
+                Cam2Btn.Visibility = Visibility.Visible;
+                Cam3Btn.Visibility = Visibility.Visible;
+                Cam4Btn.Visibility = Visibility.Collapsed;
+                if (!(MessageBus.SeetingNowLoadInMaThreadsIndex > 0 && MessageBus.SeetingNowLoadInMaThreadsIndex < 3))
+                {
+                    Cam1Btn_Click(null, null);
+                }
+            }
+            else if(CamNumCoBox.SelectedItem.ToString() == "四相机")
+            {
+                Cam1Btn.Visibility = Visibility.Visible;
+                Cam2Btn.Visibility = Visibility.Visible;
+                Cam3Btn.Visibility = Visibility.Visible;
+                Cam4Btn.Visibility = Visibility.Visible;
+            }
+        }
+
+        private void Cam1Btn_Click(object sender, RoutedEventArgs e)
+        {
+            if (MessageBus.MainThreadS == null|| MessageBus.MainThreadS.Count<1|| MessageBus.MainThreadS[0] == null)
+                return;
+            MessageBus.SeetingNowLoadInMaThreadsIndex = 0;
+            MessageBus.NowSettingLoadMainThread = MessageBus.MainThreadS[0];
+        }
+
+        private void Cam2Btn_Click(object sender, RoutedEventArgs e)
+        {
+            //MessageBus.ShowBondage.ExposureTimeValue = "300";
+            MessageBox.Show($"NowThread.ETime:{MessageBus.NowSettingLoadMainThread.cameraConfig.ExposureTimeValue},Thread[0].ETime:{MessageBus.MainThreadS[0].cameraConfig.ExposureTimeValue}");
+        }
+
+        private void CameraSettingBtn_Click(object sender, RoutedEventArgs e)
+        {
+            CameraSettingGrid.Visibility = Visibility.Visible;
+            ShuLiSettingGrid.Visibility = Visibility.Collapsed;
+        }
+
+        private void ShuLiSettingBtn_Click(object sender, RoutedEventArgs e)
+        {
+            CameraSettingGrid.Visibility = Visibility.Collapsed;
+            ShuLiSettingGrid.Visibility = Visibility.Visible;
+        }
+
+        private void CamListFlushBtn_Click(object sender, RoutedEventArgs e)
+        {
+            List<CameraInfoClass> CameraInfoList = new List<CameraInfoClass>();
+            MessageBus.CameraClass.GetCameraList(out CameraInfoList);
+            if (CameraInfoList.Count > 0)
+            {
+                MessageBus.ShowBinding.CameraItems.Clear();
+                MessageBus.ShowBinding.CameraItems.Add(new CameraCoboxItem() { Name = "请选择相机", SNValue = "" });
+                foreach (var item in CameraInfoList)
+                {
+                    MessageBus.ShowBinding.CameraItems.Add(new CameraCoboxItem()
+                    {
+                        Name = item.DeviceName + "_" + item.DeviceSN,
+                        SNValue = item.DeviceSN
+                    });
+                }
+                CamSelectConBox.SelectedValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+            }
+        }
+
+        private void CamSelectConBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            if(MessageBus.ShowBinding.CameraItems.Count == 0) return;
+            string ThisItemSN = MessageBus.ShowBinding.CameraSNNum;
+            if (MessageBus.NowSettingLoadMainThread == null || ThisItemSN == MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum) return;
+            if (ThisItemSN != string.Empty && ThisItemSN != null)
+            {
+                if (MessageBus.NowSettingLoadMainThread.CameraRunStatic)
+                {
+                    var confirmResult = MessageBox.Show("检测到正在识别,切换相机需要关闭识别,是否继续切换",
+                                      "切换确认", MessageBoxButton.YesNo);
+                    if (confirmResult == MessageBoxResult.No)
+                    {
+                        CamSelectConBox.SelectedValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+                        return;
+                    }
+                    MessageBus.NowSettingLoadMainThread.StopMianThread();
+                }
+                if (MessageBus.NowSettingLoadMainThread.ReLoadCamera(ThisItemSN))
+                {
+                    MessageBus.NowSettingLoadMainThread.GetCameraConfig();
+                    MessageBus.ShowBinding.ImageWidth = MessageBus.NowSettingLoadMainThread.cameraConfig.Width.ToString();
+                    MessageBus.ShowBinding.ImageHeight = MessageBus.NowSettingLoadMainThread.cameraConfig.Height.ToString();
+                    MessageBus.ShowBinding.CamUserName = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraName;
+                    MessageBus.ShowBinding.CamOffsetX = MessageBus.NowSettingLoadMainThread.cameraConfig.OffsetX.ToString();
+                    MessageBus.ShowBinding.ExposureTimeValue = MessageBus.NowSettingLoadMainThread.cameraConfig.ExposureTimeValue.ToString();
+                    MessageBus.ShowBinding.AcquistionLineRate = MessageBus.NowSettingLoadMainThread.cameraConfig.AcquistionLineRateValue.ToString();
+                    MessageBus.ShowBinding.CameraSNNum = ThisItemSN;
+                }
+                else
+                {
+                    MessageBox.Show("切换相机失败!");
+                    CamSelectConBox.SelectedItem = MessageBus.NowSettingLoadMainThread.cameraConfig.DeviceName + "_" + MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+                    return;
+                }
+            }
+            else
+            {
+                if (MessageBus.NowSettingLoadMainThread.CameraRunStatic)
+                {
+                    var confirmResult = MessageBox.Show("检测到正在识别,切换相机需要关闭识别,是否继续切换",
+                                      "切换确认", MessageBoxButton.YesNo);
+                    if (confirmResult == MessageBoxResult.No)
+                    {
+                        CamSelectConBox.SelectedValue = MessageBus.NowSettingLoadMainThread.cameraConfig.CameraSNNum;
+                        return;
+                    }
+                    MessageBus.NowSettingLoadMainThread.StopMianThread();
+                }
+                else
+                {
+                    MessageBus.NowSettingLoadMainThread.DisposeCamera();
+                }
+                MessageBus.ShowBinding.ImageWidth = "0";
+                MessageBus.ShowBinding.ImageHeight = "0";
+                MessageBus.ShowBinding.CamUserName = string.Empty;
+                MessageBus.ShowBinding.CamOffsetX = "0";
+                MessageBus.ShowBinding.ExposureTimeValue = "0";
+                MessageBus.ShowBinding.AcquistionLineRate = "0";
+                MessageBus.ShowBinding.CameraSNNum = null;
+            }
+        }
+
+        private void CheckModel1RadBtn_Checked(object sender, RoutedEventArgs e)
+        {
+            MessageBus.ShowBinding.PandingCode = "-1";
+            WHParaPanel.Visibility = Visibility.Collapsed;
+            AreaParaPanel.Visibility = Visibility.Collapsed;
+        }
+
+        private void CheckModel2RadBtn_Checked(object sender, RoutedEventArgs e)
+        {
+            MessageBus.ShowBinding.PandingCode = "0";
+            WHParaPanel.Visibility = Visibility.Visible;
+            AreaParaPanel.Visibility = Visibility.Collapsed;
+        }
+
+        private void CheckModel3RadBtn_Checked(object sender, RoutedEventArgs e)
+        {
+            MessageBus.ShowBinding.PandingCode = "1";
+            WHParaPanel.Visibility = Visibility.Collapsed;
+            AreaParaPanel.Visibility = Visibility.Visible;
+        }
+
+        private void CheckModel4RadBtn_Checked(object sender, RoutedEventArgs e)
+        {
+            MessageBus.ShowBinding.PandingCode = "2";
+            WHParaPanel.Visibility = Visibility.Visible;
+            AreaParaPanel.Visibility = Visibility.Visible;
+        }
+
+        private void SaveAllConfigBtn_Click(object sender, RoutedEventArgs e)
+        {
+            List<SaveConfigModel> SaveConfig = new List<SaveConfigModel>();
+            if(MessageBus.MainThreadS.Count <= 0)
+            {
+                return;
+            }
+            foreach (var item in MessageBus.MainThreadS)
+            {
+                SaveConfig.Add(new SaveConfigModel()
+                {
+                    CameraConfig = item.cameraConfig,
+                    ShuLiConfigClass = item.shuLiConfig
+                });
+            }
+            if (!Directory.Exists(".\\Config\\")) Directory.CreateDirectory(".\\Config\\");
+            {
+                XmlStorage.SerializeToXml(SaveConfig, ".\\Config\\CCDCountConfig.xml");
+            }
+        }
+    }
+}

+ 51 - 0
CCDCountWpf/WpfPage/UserManagementPage.xaml

@@ -0,0 +1,51 @@
+<Page x:Class="CCDCountWpf.WpfPage.UserManagementPage"
+      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+      xmlns:local="clr-namespace:CCDCountWpf.WpfPage"
+      mc:Ignorable="d" 
+      d:DesignHeight="450" d:DesignWidth="800"
+      Title="UserManagementPage">
+    <Grid>
+        <Grid Height="30" VerticalAlignment="Top">
+            <StackPanel Orientation="Horizontal">
+                <Button x:Name="AddUserBtn" HorizontalAlignment="Left" Height="25" Width="25" Background="{x:Null}" Click="AddUserBtn_Click">
+                    <StackPanel Orientation="Vertical">
+                        <Image  Source="/FromImage/用户增加.png"/>
+                    </StackPanel>
+                </Button>
+                <Button x:Name="DeleteUserBtn" HorizontalAlignment="Left" Height="25" Width="25" Background="{x:Null}" Click="DeleteUserBtn_Click">
+                    <StackPanel Orientation="Vertical">
+                        <Image  Source="/FromImage/用户删除.png"/>
+                    </StackPanel>
+                </Button>
+                <Button x:Name="ChangeUserBtn" HorizontalAlignment="Left" Height="25" Width="25" Background="{x:Null}" Click="ChangeUserBtn_Click">
+                    <StackPanel Orientation="Vertical">
+                        <Image  Source="/FromImage/用户修改.png"/>
+                    </StackPanel>
+                </Button>
+            </StackPanel>
+        </Grid>
+        <DataGrid x:Name="UserMessageDataGrid" ItemsSource="{Binding UserMesDataModels}" AutoGenerateColumns="False" Margin="0,30,0,0" SelectionMode="Single"
+            SelectionUnit="FullRow" SelectionChanged="DataGrid_SelectionChanged">
+            <!-- 添加行样式 -->
+            <DataGrid.RowStyle>
+                <Style TargetType="DataGridRow">
+                    <Style.Triggers>
+                        <Trigger Property="IsSelected" Value="True">
+                            <!-- 设置蓝色背景和白色文字 -->
+                            <Setter Property="Background" Value="DodgerBlue"/>
+                            <Setter Property="Foreground" Value="White"/>
+                        </Trigger>
+                    </Style.Triggers>
+                </Style>
+            </DataGrid.RowStyle>
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="ID" Binding="{Binding Id}" />
+                <DataGridTextColumn Header="用户名" Binding="{Binding UserName}" />
+                <DataGridTextColumn Header="用户信息" Binding="{Binding UserMes}" />
+            </DataGrid.Columns>
+        </DataGrid>
+    </Grid>
+</Page>

+ 81 - 0
CCDCountWpf/WpfPage/UserManagementPage.xaml.cs

@@ -0,0 +1,81 @@
+using CCDCount.MODEL.SqlDataModel;
+using CCDCountWpf.WpfFrom;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace CCDCountWpf.WpfPage
+{
+    /// <summary>
+    /// UserManagementPage.xaml 的交互逻辑
+    /// </summary>
+    public partial class UserManagementPage : Page
+    {
+        UserMesDataModelClass SelectUserMessage = null;
+        public UserManagementPage()
+        {
+            InitializeComponent();
+            DataContext = MessageBus.ShowBinding;
+            MessageBus.ShowBinding.UserMesDataModels = MessageBus.UserMessageClass.GetAllUserMessage();
+        }
+
+        private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            var selectedItem = UserMessageDataGrid.SelectedItem as UserMesDataModelClass; // 替换为实际数据类型
+            if (selectedItem != null)
+            {
+                SelectUserMessage = selectedItem;
+            }
+        }
+
+        private void ChangeUserBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (SelectUserMessage.Id == 1&&MessageBus.NowLoginUserMessage.Id != 1)
+            {
+                MessageBox.Show("权限不足,不可操作Admin用户");
+                return;
+            }
+            if (SelectUserMessage == null)
+            {
+                MessageBox.Show("请选择用户");
+                return;
+            }
+            ChangeUserWindow changeUserWindow = new ChangeUserWindow();
+            changeUserWindow.UserMessage = SelectUserMessage;
+            changeUserWindow.ShowDialog();
+        }
+
+        private void DeleteUserBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (SelectUserMessage.Id == 1)
+            {
+                MessageBox.Show("Admin管理员账户,不可删除");
+                return;
+            }
+            if (SelectUserMessage == null)
+            {
+                MessageBox.Show("请选择用户");
+                return;
+            }
+            MessageBus.UserMessageClass.DeleteUserMessage(SelectUserMessage.Id);
+            MessageBus.ShowBinding.UserMesDataModels = MessageBus.UserMessageClass.GetAllUserMessage();
+        }
+
+        private void AddUserBtn_Click(object sender, RoutedEventArgs e)
+        {
+            AddUserWindow addUserWindow = new AddUserWindow();
+            addUserWindow.ShowDialog();
+        }
+    }
+}

+ 9 - 0
CCDCountWpf/packages.config

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="EntityFramework" version="6.4.4" targetFramework="net48" />
+  <package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.Core" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.EF6" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.Linq" version="1.0.119.0" targetFramework="net48" />
+</packages>

+ 38 - 0
TestWork.DLL/CCDCount.DLL.csproj

@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.props" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" />
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -12,6 +13,8 @@
     <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <Deterministic>true</Deterministic>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <DebugSymbols>true</DebugSymbols>
@@ -35,6 +38,12 @@
     <Reference Include="CsvHelper, Version=33.0.0.0, Culture=neutral, PublicKeyToken=8c4959082be5c823, processorArchitecture=MSIL">
       <HintPath>..\packages\CsvHelper.33.0.1\lib\net48\CsvHelper.dll</HintPath>
     </Reference>
+    <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="EntityFramework.SqlServer, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL">
+      <HintPath>..\packages\EntityFramework.6.4.4\lib\net45\EntityFramework.SqlServer.dll</HintPath>
+    </Reference>
     <Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=8.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.8.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
     </Reference>
@@ -45,11 +54,25 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>DLL\MvCameraControl.Net.dll</HintPath>
     </Reference>
+    <Reference Include="NModbus, Version=3.0.81.0, Culture=neutral, processorArchitecture=MSIL">
+      <HintPath>..\packages\NModbus.3.0.81\lib\net46\NModbus.dll</HintPath>
+    </Reference>
+    <Reference Include="PresentationCore" />
     <Reference Include="System" />
     <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
     </Reference>
+    <Reference Include="System.ComponentModel.DataAnnotations" />
     <Reference Include="System.Core" />
+    <Reference Include="System.Data.SQLite, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\lib\net46\System.Data.SQLite.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.EF6, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Data.SQLite.EF6.1.0.119.0\lib\net46\System.Data.SQLite.EF6.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Data.SQLite.Linq, Version=1.0.119.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Data.SQLite.Linq.1.0.119.0\lib\net46\System.Data.SQLite.Linq.dll</HintPath>
+    </Reference>
     <Reference Include="System.Drawing" />
     <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>..\packages\System.Memory.4.5.0\lib\netstandard2.0\System.Memory.dll</HintPath>
@@ -75,7 +98,9 @@
     <Compile Include="BottingClass.cs" />
     <Compile Include="CameraClass.cs" />
     <Compile Include="Delta\DeltaClass.cs" />
+    <Compile Include="FaultLogClass.cs" />
     <Compile Include="MechanicalControlClass.cs" />
+    <Compile Include="SqlDataClass\UserMessSqliteDataClass.cs" />
     <Compile Include="Tools\IniFileClass.cs" />
     <Compile Include="Tools\LoadSplieImageClass.cs" />
     <Compile Include="Tools\LogClass.cs" />
@@ -84,6 +109,9 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Delta\EtherCAT_DLL.cs" />
     <Compile Include="Delta\EtherCAT_DLL_Err.cs" />
+    <Compile Include="Tools\ModbusClass.cs" />
+    <Compile Include="SqlDataClass\ErrorMesSqliteDataClass.cs" />
+    <Compile Include="Tools\SystemMonitorClass.cs" />
     <Compile Include="Tools\XMLFileClass.cs" />
     <Compile Include="ZhengYunDong\Zmcaux.cs" />
     <Compile Include="ZhengYunDong\ZmcauxClass.cs" />
@@ -105,4 +133,14 @@
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.props'))" />
+    <Error Condition="!Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\EntityFramework.6.4.4\build\EntityFramework.targets'))" />
+    <Error Condition="!Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets'))" />
+  </Target>
+  <Import Project="..\packages\EntityFramework.6.4.4\build\EntityFramework.targets" Condition="Exists('..\packages\EntityFramework.6.4.4\build\EntityFramework.targets')" />
+  <Import Project="..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets" Condition="Exists('..\packages\Stub.System.Data.SQLite.Core.NetFramework.1.0.119.0\build\net46\Stub.System.Data.SQLite.Core.NetFramework.targets')" />
 </Project>

+ 68 - 25
TestWork.DLL/CameraClass.cs

@@ -27,10 +27,7 @@ namespace CCDCount.DLL
 
         private List<IDeviceInfo> CamList;      // 相机列表
         private IDevice device = null;          // 相机实例
-        private Thread receiveThread = null;    // 接收图像线程
         private ConcurrentQueue<IFrameOut> FrameOuts = new ConcurrentQueue<IFrameOut>();
-        private ConcurrentQueue<byte[]> ImageBytes = new ConcurrentQueue<byte[]>(); //图像接受队列
-        private int OnImageSelectRows = 20;
         private long lastframeNum = -1;
 
         public int CamereNo { get { return _cameraNo; } }
@@ -91,6 +88,12 @@ namespace CCDCount.DLL
         public bool LoadCamereDevice(CameraConfig DeviceConfig)
         {
             bool Blresult = false;
+            if (device != null && device.IsConnected)
+            {
+                device.Close();
+                device.Dispose();
+            }
+            UpdateCameraList();
             List<IDeviceInfo> deviceInfos = CamList.Where(o => o.SerialNumber == DeviceConfig.CameraSNNum).ToList();
             if(deviceInfos.Count == 0) return  Blresult;
             IDeviceInfo deviceInfo = deviceInfos.First();
@@ -101,14 +104,14 @@ namespace CCDCount.DLL
             }
             catch (Exception ex)
             {
-                LOG.error("Create Device fail!" + ex.Message);
+                FaultLog.RecordErrorMessage("Create Device fail!" + DeviceConfig.CameraSNNum + ":" + ex.Message);
                 return Blresult;
             }
 
             int result = device.Open();
             if (result != MvError.MV_OK)
             {
-                LOG.error("Open Device fail!" + result);
+                FaultLog.RecordErrorMessage("Open Device fail!" + DeviceConfig.CameraSNNum + ":" + result);
                 return Blresult;
             }
 
@@ -119,8 +122,7 @@ namespace CCDCount.DLL
                 IGigEDevice gigEDevice = device as IGigEDevice;
 
                 // 探测网络最佳包大小(只对GigE相机有效)
-                int optionPacketSize;
-                result = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
+                result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
                 if (result != MvError.MV_OK)
                 {
                     //Log("Warning: Get Packet Size failed!", result);
@@ -180,7 +182,7 @@ namespace CCDCount.DLL
             }
             catch (Exception ex)
             {
-                LOG.error("Create Device fail!" + ex.Message);
+                FaultLog.RecordErrorMessage("Create Device fail!" + CameraSN + ":" + ex.Message);
                 return Blresult;
             }
 
@@ -188,7 +190,7 @@ namespace CCDCount.DLL
             if (result != MvError.MV_OK)
             {
                 Blresult = false;
-                LOG.error("Open Device fail!" + result);
+                FaultLog.RecordErrorMessage("Open Device fail!" + CameraSN + ":" + result);
                 return Blresult;
             }
 
@@ -199,8 +201,7 @@ namespace CCDCount.DLL
                 IGigEDevice gigEDevice = device as IGigEDevice;
 
                 // 探测网络最佳包大小(只对GigE相机有效)
-                int optionPacketSize;
-                result = gigEDevice.GetOptimalPacketSize(out optionPacketSize);
+                result = gigEDevice.GetOptimalPacketSize(out int optionPacketSize);
                 if (result != MvError.MV_OK)
                 {
                     //Log("Warning: Get Packet Size failed!", result);
@@ -217,6 +218,34 @@ namespace CCDCount.DLL
             return Blresult;
         }
 
+        /// <summary>
+        /// 重新加载相机参数
+        /// </summary>
+        /// <param name="RecameraConfig"></param>
+        /// <returns></returns>
+        public bool ReLoadCameraConfig(CameraConfig RecameraConfig)
+        {
+            bool Blresult = false;
+            if (device != null && device.IsConnected)
+            {
+                //设置从配置文件读取的参数
+                device.Parameters.GetStringValue("DeviceModelName", out IStringValue deviceModelName);
+                _cameraNo = RecameraConfig.CamerNo;
+                if (RecameraConfig.CameraName != deviceModelName.CurValue)
+                    device.Parameters.SetStringValue("DeviceUserID", RecameraConfig.CameraName);
+                device.Parameters.SetFloatValue("ExposureTime", RecameraConfig.ExposureTimeValue);
+                device.Parameters.SetIntValue("AcquisitionLineRate", RecameraConfig.AcquistionLineRateValue);
+                device.Parameters.SetIntValue("Height", RecameraConfig.Height);
+                device.Parameters.SetIntValue("Width", RecameraConfig.Width);
+                device.Parameters.SetIntValue("OffsetX", RecameraConfig.OffsetX);
+                // 设置采集连续模式
+                device.Parameters.SetEnumValueByString("AcquisitionMode", "Continuous");
+                device.Parameters.SetEnumValueByString("TriggerMode", "Off");
+                Blresult = true;
+            }
+            return Blresult;
+        }
+
         /// <summary>
         /// 开启相机采集
         /// </summary>
@@ -232,7 +261,14 @@ namespace CCDCount.DLL
         {
             StopReceiveFuntion();
             //StopEventGetImage();
-            if(device!=null)
+        }
+
+        /// <summary>
+        /// 释放相机资源
+        /// </summary>
+        public void DisPoseCamera()
+        {
+            if (device != null)
             {
                 int result = device.StreamGrabber.StopGrabbing();
                 device.Close();
@@ -242,8 +278,13 @@ namespace CCDCount.DLL
                     LOG.log(("Stop Grabbing Fail!", result));
                 }
             }
-
         }
+
+        /// <summary>
+        /// 获取一次图片
+        /// </summary>
+        /// <param name="IFrameData"></param>
+        /// <returns></returns>
         public bool GetOnceImage(out IFrameOut IFrameData)
         {
             bool result = false;
@@ -277,22 +318,20 @@ namespace CCDCount.DLL
         public CameraImageSizeClass GetCamereImageSize()
         { 
             CameraImageSizeClass cameraImageSize =new CameraImageSizeClass();
-            IIntValue PixWidth;
-            IIntValue PixHeight;
-            device.Parameters.GetIntValue("Width", out PixWidth);
-            device.Parameters.GetIntValue("Height", out PixHeight);
+            device.Parameters.GetIntValue("Width", out IIntValue PixWidth);
+            device.Parameters.GetIntValue("Height", out IIntValue PixHeight);
             cameraImageSize.Height = (int)PixHeight.CurValue;
             cameraImageSize.Width = (int)PixWidth.CurValue;
             return cameraImageSize;
         }
 
         /// <summary>
-        /// 获取Config信息
+        /// 获取当前相机的参数生成Config信息
         /// </summary>
         /// <returns></returns>
         public CameraConfig GetConfigValue()
         { 
-            CameraConfig result = null;
+            CameraConfig result;
             device.Parameters.GetFloatValue("ExposureTime", out IFloatValue exposureTime);
             device.Parameters.GetIntValue("AcquisitionLineRate", out IIntValue acquisitionLineRate);
             device.Parameters.GetIntValue("OffsetX", out IIntValue offsetX);
@@ -328,7 +367,7 @@ namespace CCDCount.DLL
 
         public bool IsLoadCamera()
         {
-            return device ==  null ? false : true;
+            return device != null;
         }
 
         public bool IsConnectCamera()
@@ -346,18 +385,22 @@ namespace CCDCount.DLL
         /// <summary>
         /// 开启采集
         /// </summary>
-        private void StartReceiveFuntion()
+        private bool StartReceiveFuntion()
         {
+            bool result = false;
             try
             {
-                device.StreamGrabber.SetImageNodeNum(100);
+                if(device == null) return result;
+                device.StreamGrabber.SetImageNodeNum(10);
                 device.StreamGrabber.StartGrabbing();
+                result = true;
             }
             catch (Exception ex)
             {
-                LOG.error("Start thread failed!, " + ex.Message);
+                FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
                 throw;
             }
+            return result;
         }
 
         /// <summary>
@@ -371,13 +414,13 @@ namespace CCDCount.DLL
                 int ret = device.StreamGrabber.StopGrabbing();
                 if (ret != MvError.MV_OK)
                 {
-                    LOG.error(("Stop grabbing failed:{0:x8}", ret));
+                    FaultLog.RecordErrorMessage($"Stop grabbing failed:{ret:x8}");
                     return;
                 }
             }
             catch (Exception ex)
             {
-                LOG.error("Stop thread failed!, " + ex.Message);
+                FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
                 throw;
             }
         }

+ 109 - 0
TestWork.DLL/FaultLogClass.cs

@@ -0,0 +1,109 @@
+using CCDCount.DLL.SqlDataClass;
+using CCDCount.MODEL.ShuLiClass;
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.DLL
+{
+    public class FaultLog
+    {
+        static ErrorMesSqliteDataClass errorMesSqliteDataClass = null;
+        static string dbPath = $"{AppDomain.CurrentDomain.BaseDirectory}DATA\\FaultMessage{DateTime.Now:yyyyMMdd}.db";
+        static int userid = 0;
+        static int SaveLogLevel = 5;
+
+        static FaultLog()
+        {
+            errorMesSqliteDataClass = new ErrorMesSqliteDataClass(dbPath);
+        }
+
+        public static void SetUserID(int id)
+        {
+            userid = id;
+        }
+
+        /// <summary>
+        /// 记录错误信息
+        /// </summary>
+        /// <param name="Message"></param>
+        /// <param name="userid"></param>
+        public static void RecordErrorMessage(string Message)
+        {
+            ErroeMesDataModelClass errorMessage = new ErroeMesDataModelClass
+            {
+                Message = Message,
+                DateTime = DateTime.Now,
+                Category = "系统",
+                MessageType = "异常",
+                UserID = userid
+            };
+            errorMesSqliteDataClass.InsertErrMessage(errorMessage);
+        }
+
+        public static void RecordLogMessage(string Message,int LogLevel)
+        {
+            if (LogLevel < SaveLogLevel)
+            {
+                return;
+            }
+            ErroeMesDataModelClass errorMessage = new ErroeMesDataModelClass
+            {
+                Message = Message,
+                DateTime = DateTime.Now,
+                Category = "系统",
+                MessageType = "日志",
+                UserID = userid
+            };
+            errorMesSqliteDataClass.InsertErrMessage(errorMessage);
+        }
+
+        /// <summary>
+        /// 记录更改信息
+        /// </summary>
+        /// <param name="Message"></param>
+        /// <param name="userid"></param>
+        public static void RecordValueChangeMessage(string Message)
+        {
+            ErroeMesDataModelClass errorMessage = new ErroeMesDataModelClass
+            {
+                Message = Message,
+                DateTime = DateTime.Now,
+                Category = "系统",
+                MessageType = "值变更",
+                UserID = userid
+            };
+            errorMesSqliteDataClass.InsertErrMessage(errorMessage);
+        }
+
+        /// <summary>
+        /// 记录值保存信息
+        /// </summary>
+        /// <param name="Message"></param>
+        /// <param name="userid"></param>
+        public static void RecordValueSaveMessage(string Message)
+        {
+            ErroeMesDataModelClass errorMessage = new ErroeMesDataModelClass
+            {
+                Message = Message,
+                DateTime = DateTime.Now,
+                Category = "系统",
+                MessageType = "值保存",
+                UserID = userid
+            };
+            errorMesSqliteDataClass.InsertErrMessage(errorMessage);
+        }
+
+        /// <summary>
+        /// 读取全部信息
+        /// </summary>
+        /// <returns></returns>
+        public static List<ErroeMesDataModelClass> GetAllErrMessage()
+        {
+            return errorMesSqliteDataClass.GetAllErrMessage();
+        }
+    }
+}

+ 338 - 176
TestWork.DLL/MainThreadClass.cs

@@ -1,15 +1,19 @@
-using CCDCount.MODEL.CameraClass;
+using CCDCount.DLL.Tools;
+using CCDCount.MODEL.CameraClass;
 using CCDCount.MODEL.ConfigModel;
 using CCDCount.MODEL.ShuLiClass;
 using LogClass;
 using MvCameraControl;
 using System;
+using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Drawing;
 using System.IO;
 using System.Linq;
+using System.Runtime.InteropServices;
 using System.Runtime.Remoting.Messaging;
+using System.Text;
 using System.Threading;
 
 namespace CCDCount.DLL
@@ -21,16 +25,15 @@ namespace CCDCount.DLL
         private bool IsSwitch = false;
         public ShuLiClass shuLiClass = null;
         CameraClass cameraClass = new CameraClass();
-        public string ThisCameraDevice  = string.Empty;
-        public string ThisCameraSN = string.Empty;
-        public string ThisCamerName = string.Empty;
+        public ShuLiConfigClass shuLiConfig = null;
+        public CameraConfig cameraConfig = null;
+        public bool CameraConfigIsChange = false;
         public int ThisCamerNo = -1;
-        //留给主界面的回调函数
-        public event EventHandler<ActiveObjectEventArgsClass> WorkerToFrom;
 
         public bool CameraStatic { get { return _CameraStatic; } }
         private bool _CameraStatic = false;
 
+        // 返回交换线程状态
         public bool CameraRunStatic { get { return IsSwitch; } }
 
         public bool IsOpenLoadThread { get  { return _IsOpenLoadThread; }}
@@ -40,9 +43,15 @@ namespace CCDCount.DLL
         public int OkHistoryNum { get { return shuLiClass.GetOkHistoryNum(); } }
         public int NgHistoryNum { get { return shuLiClass.GetNgHistoryNum(); } }
 
-        ZmcauxClass zmcauxClass = new ZmcauxClass();
-        //private BottingClass Botting = new BottingClass();
-        //private MechanicalControlClass  MechanicalControl = new MechanicalControlClass();
+        // 数粒信息发送线程
+        Thread SendBottLogicMessageThread = null;
+        bool IsSend = false;
+
+        // Modbus客户端实例
+        ModbusTcpClient modbusTcpClient = null;
+
+        // 颗粒结果待发送队列
+        ConcurrentQueue<ushort> SendQueue = new ConcurrentQueue<ushort>();
 
         /// <summary>
         /// 数粒状态计时器
@@ -53,16 +62,44 @@ namespace CCDCount.DLL
         /// </summary>
         private bool _ShuLiState = true;
         public bool ShuLiState { get { return _ShuLiState; } }
+
+        private bool IsDebug = false;
+        private bool IsConnectModbus = false;
         #endregion
 
         #region 公共方法
+        /// <summary>
+        /// 设置ModbusTcpClient
+        /// </summary>
+        /// <param name="modbusTcpClient"></param>
+        public void SetModbusClient(ModbusTcpClient modbusTcpClient)
+        {
+            this.modbusTcpClient = modbusTcpClient;
+            if (!this.modbusTcpClient.IsTcpClientConnected())
+            {
+                FaultLog.RecordErrorMessage("ModbusTcpClient Connect Failed!");
+            }
+            else
+            {
+                FaultLog.RecordLogMessage("ModbusTcpClient Connect Success!", 6);
+                IsConnectModbus = true;
+            }
+        }
+
+        /// <summary>
+        /// 初始化构造方法
+        /// </summary>
+        /// <param name="configClass"></param>
+        /// <param name="CameraConfig"></param>
         public MainThreadClass(ShuLiConfigClass configClass,CameraConfig CameraConfig)
         {
+            shuLiConfig = configClass;
+            cameraConfig = CameraConfig;
             // 数粒配置文件地址
             if (configClass!=null)
             {
                 // 创建数粒对象(配置文件)
-                shuLiClass = new ShuLiClass(configClass);
+                shuLiClass = new ShuLiClass(shuLiConfig);
             }
             else
             {
@@ -70,117 +107,134 @@ namespace CCDCount.DLL
                 shuLiClass = new ShuLiClass();
             }
 
-            _IsOpenLoadThread = CameraConfig.IsOpenLoad;
-            ThisCameraSN = CameraConfig.CameraSNNum;
-            ThisCamerName = CameraConfig.CameraName;
-            ThisCameraDevice =  CameraConfig.DeviceName;
-            ThisCamerNo = CameraConfig.CamerNo;
+            _IsOpenLoadThread = cameraConfig.IsOpenLoad;
+            ThisCamerNo = cameraConfig.CamerNo;
         }
-        /// <summary>
-        /// 开始主线程
-        /// </summary>
-        public bool StartMianThread(CameraConfig DeviceConfig)
+
+        public bool LoadCamera()
         {
             bool result = false;
             // 相机列表
-            List<CameraInfoClass> list = new List<CameraInfoClass>();
-            // 获取相机列表
-            cameraClass.GetCameraList(out list);
-            if (list.Count == 0)
+            try
             {
-                LOG.error(string.Format("{0}:没有相机", "MainThreadClass-StartMianThread"));
-                // 如果没有相机,则退出
-                return result;
+                // 获取相机列表
+                cameraClass.GetCameraList(out List<CameraInfoClass> list);
+                if (list.Count == 0)
+                {
+                    FaultLog.RecordErrorMessage(string.Format("{0}:没有相机", "MainThreadClass-StartMianThread"));
+                    // 如果没有相机,则退出
+                    return result;
+                }
+                // 加载相机
+                // cameraClass.LoadCamereDevice(list.First().DeviceSN);
+                if (!cameraClass.LoadCamereDevice(cameraConfig))
+                {
+                    FaultLog.RecordErrorMessage(string.Format("{0}:相机加载失败", "MainThreadClass-StartMianThread"));
+                    return result;
+                }
+                CameraConfigIsChange = false;
             }
-            // 加载相机
-            // cameraClass.LoadCamereDevice(list.First().DeviceSN);
-            if(!cameraClass.LoadCamereDevice(DeviceConfig))
+            catch
             {
-                LOG.error(string.Format("{0}:相机加载失败", "MainThreadClass-StartMianThread"));
-                return result;
+
             }
-            // 取图线程开启
-            cameraClass.StartCamera();
-            _CameraStatic = true;
-            // 数据交换线程开启
-            StartSwitchThread();
-            // 为数粒算法的识别成功一粒回调函数添加方法
-            shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
-            // 开启识别线程
-            shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width);
-            zmcauxClass.OpenZmcauxCard();
-            result = true;
             return result;
         }
 
+        public void ReLoadCameraConfig()
+        {
+            if(CameraConfigIsChange)
+            {
+                CameraConfig  OldcameraConfig = cameraClass.GetConfigValue();
+                if(OldcameraConfig.CameraSNNum != cameraConfig.CameraSNNum)
+                {
+                    cameraClass.LoadCamereDevice(cameraConfig);
+                }
+                else
+                {
+                    cameraClass.ReLoadCameraConfig(cameraConfig);
+                }
+            }
+        }
+
         /// <summary>
         /// 开始主线程
         /// </summary>
         public bool StartMianThread()
         {
             bool result = false;
-            // 相机列表
-            List<CameraInfoClass> list = new List<CameraInfoClass>();
-            // 获取相机列表
-            cameraClass.GetCameraList(out list);
-            if (list.Count == 0)
+            try
             {
-                // 如果没有相机,则退出
-                return result;
+                // 取图线程开启
+                cameraClass.StartCamera();
+                _CameraStatic = true;
+                StartSendBottLogicMessageThread();
+                // 数据交换线程开启
+                StartSwitchThread();
+                // 为数粒算法的识别成功一粒回调函数添加方法
+                shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
+                // 开启识别线程
+                shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width);
+                result = true;
+            }
+            catch
+            {
+
             }
-            // 为数粒算法的识别成功一粒回调函数添加方法
-            shuLiClass.WorkCompleted += Worker_OneGrainCompleted;
-            // 加载相机
-            if (!cameraClass.LoadCamereDevice(new CameraConfig() { CameraSNNum = list.First().DeviceSN}))
-                return result;
-            _CameraStatic = true;
-            // 取图线程开启
-            cameraClass.StartCamera();
-            // 数据交换线程开启
-            StartSwitchThread();
-            // 开启识别线程
-            shuLiClass.StartIdentifyFuntion(cameraClass.GetCamereImageSize().Width);
-            zmcauxClass.OpenZmcauxCard();
-            result = true;
             return result;
         }
+
         /// <summary>
         /// 停止主线程
         /// </summary>
-        public void StopMianThread()
+        public bool StopMianThread()
+        {
+            bool result = false;
+            try
+            {
+                _CameraStatic = false;
+                shuLiClass.WorkCompleted -= Worker_OneGrainCompleted;
+                // 相机取图关闭
+                cameraClass.StopCamera();
+                // 数据交换线程关闭
+                StopSwitchThread();
+                // 数粒识别线程关闭
+                shuLiClass.StopIdentifyFuntion();
+                StopSendBottLogicMessageThread();
+                result = true;
+            }
+            catch
+            {
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 释放相机资源
+        /// </summary>
+        public void DisposeCamera()
         {
-            shuLiClass.WorkCompleted -= Worker_OneGrainCompleted;
-            // 相机取图线程关闭
             cameraClass.StopCamera();
-            // 数据交换线程关闭
-            StopSwitchThread();
-            // 数粒识别线程关闭
-            shuLiClass.StopIdentifyFuntion();
-            zmcauxClass.CloseZmcauxCard();
+            cameraClass.DisPoseCamera();
         }
 
+        /// <summary>
+        /// 重加载相机
+        /// </summary>
+        /// <param name="CameraSN"></param>
+        /// <returns></returns>
         public bool ReLoadCamera(string CameraSN)
         { 
             bool result = false;
             result = cameraClass.ReLoadCameraDevice(CameraSN);
             if (result)
             {
-                CameraConfig ReloadCaonfig = cameraClass.GetConfigValue();
-                ThisCameraSN = ReloadCaonfig.CameraSNNum;
-                ThisCamerName = ReloadCaonfig.CameraName;
-                ThisCameraDevice = ReloadCaonfig.DeviceName;
+                cameraConfig = cameraClass.GetConfigValue();
             }
             return  result;
              
         }
 
-        public void DisposeCamera()
-        {
-            cameraClass.StopCamera();
-            ThisCameraSN = string.Empty;
-            ThisCamerName = string.Empty;
-            ThisCameraDevice = string.Empty;
-        }
         /// <summary>
         /// 获取显示用的图片数据
         /// </summary>
@@ -199,49 +253,94 @@ namespace CCDCount.DLL
             List<ActiveObjectClass> Data = shuLiClass.GetHistoryActive().Where(o => o.LastSeenLine > NewActive.LastSeenLine - ImageHeight).ToList();
             Data.ForEach(o => o.RowsData.ForEach(p => RowsShowList.Add(p)));
             Bitmap BitmapImage = new Bitmap(NewActive.ImageWidth, ImageHeight);
-            Graphics g = Graphics.FromImage(BitmapImage);
-            Pen redPen = new Pen(Color.Red, 1);
-            List<RowStartEndCol> ShowList = RowsShowList.Where(o => o.RowsCol > NewActive.LastSeenLine - BitmapImage.Height).ToList();
-            RowsShowList.Where(o => o.RowsCol < NewActive.LastSeenLine - BitmapImage.Height).ToList().ForEach(o => RowsShowList.Remove(o));
-            RowsShowList.Clear();
-            ShowList.ForEach(o => g.DrawLine(redPen, new Point(o.StartCol, (int)(NewActive.LastSeenLine - o.RowsCol)), new Point(o.EndCol, (int)(NewActive.LastSeenLine - o.RowsCol))));
-            ShowList.Clear();
+            using (Graphics g = Graphics.FromImage(BitmapImage))
+            {
+                g.Clear(Color.White);
+                using (Pen RedPan = new Pen(Color.Red, 5))
+                {
+                    for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++)
+                    {
+                        g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height));
+                    }
+                }
+                using (Pen BlackPen = new Pen(Color.Black, 1))
+                {
+                    List<RowStartEndCol> ShowList = RowsShowList.Where(o => o.RowsCol > NewActive.LastSeenLine - BitmapImage.Height).ToList();
+                    RowsShowList.Where(o => o.RowsCol < NewActive.LastSeenLine - BitmapImage.Height).ToList().ForEach(o => RowsShowList.Remove(o));
+                    RowsShowList.Clear();
+                    ShowList.ForEach(o => g.DrawLine(BlackPen, new Point(o.StartCol, (int)(NewActive.LastSeenLine - o.RowsCol)), new Point(o.EndCol, (int)(NewActive.LastSeenLine - o.RowsCol))));
+                    ShowList.Clear();
+                }
+            }
             ImageData = BitmapImage.Clone() as Bitmap;
             BitmapImage.Dispose();
             //GC.Collect();
         }
 
+        /// <summary>
+        /// 获取无数据的图片
+        /// </summary>
+        /// <param name="ImageWidth"></param>
+        /// <param name="ImageHeight"></param>
+        /// <param name="ImageData"></param>
+        public void GetNullShowImage(int ImageWidth, int ImageHeight, out Bitmap ImageData)
+        {
+            Bitmap BitmapImage = new Bitmap(ImageWidth, ImageHeight);
+            using (Graphics g = Graphics.FromImage(BitmapImage))
+            {
+                g.Clear(Color.White);
+                using (Pen RedPan = new Pen(Color.Red, 8))
+                {
+                    for (int i = 0; i < shuLiClass.ChannelsRoi.Count - 1; i++)
+                    {
+                        g.DrawLine(RedPan, new Point(shuLiClass.ChannelsRoi[i], 0), new Point(shuLiClass.ChannelsRoi[i], BitmapImage.Height));
+                    }
+                }
+            }
+            ImageData = BitmapImage.Clone() as Bitmap;
+            BitmapImage.Dispose();
+        }
+
         /// <summary>
         /// 获取此刻的Config数据
         /// </summary>
         /// <param name="config"></param>
-        public void GetConfigValue(out CameraConfig Camconfig,out ShuLiConfigClass shuLiConfig)
+        public void GetAllConfigValue(out CameraConfig Camconfig,out ShuLiConfigClass shuLiConfig)
         {
             //判断是否加载了相机
             if(cameraClass.IsLoadCamera())
+            {
                 //获取已经加载的相机的配置
-                Camconfig = cameraClass.GetConfigValue();
+                cameraConfig = cameraClass.GetConfigValue();
+                Camconfig = cameraConfig;
+            }
             else
-                //新建一个相机配置
-                Camconfig = new CameraConfig();
+            {
+                cameraConfig = new CameraConfig();
+                Camconfig = cameraConfig;
+            }
             //读取视觉配置
             shuLiConfig = shuLiClass.GetConfigValue();
+            this.shuLiConfig = shuLiConfig;
         }
 
         /// <summary>
         /// 获取相机此刻的Config数据
         /// </summary>
         /// <param name="CameraConfig"></param>
-        public void GetCameraConfig(out CameraConfig CameraConfig)
+        public CameraConfig GetCameraConfig()
         {
+            CameraConfig result = null;
             //判断是否加载了相机
             if (cameraClass.IsLoadCamera())
+            {
                 //获取已经加载的相机的配置
-                CameraConfig = cameraClass.GetConfigValue();
-            else
-                //新建一个相机配置
-                CameraConfig = new CameraConfig();
+                result = cameraClass.GetConfigValue();
+                cameraConfig = result;
+            }
+            return result;
         }
+
         /// <summary>
         /// 保存所有Config
         /// </summary>
@@ -262,9 +361,28 @@ namespace CCDCount.DLL
             return result;
         }
 
-        public void Dispose()
+        /// <summary>
+        /// 清除历史数据
+        /// </summary>
+        /// <returns></returns>
+        public bool ClearHistoryActive()
         {
-            //MechanicalControl.Dispose();
+            bool result = false;
+            if(shuLiClass != null)
+                result = shuLiClass.ClearHistoryActive();
+            return result;
+        }
+
+        /// <summary>
+        /// 获取过去一秒内颗粒数量
+        /// </summary>
+        /// <returns></returns>
+        public int GetOneSecondActiveNum()
+        {
+            int result = 0;
+            if(shuLiClass != null)
+                result = shuLiClass.GetHistoryActive().Where(o=>o.EndCheckTime>DateTime.Now-TimeSpan.FromSeconds(1)).Count();
+            return result;
         }
         #endregion
 
@@ -280,7 +398,9 @@ namespace CCDCount.DLL
         /// <param name="e"></param>
         private void Worker_OneGrainCompleted(object sender, ActiveObjectEventArgsClass e)
         {
-            LOG.log("有活跃物体转换为了历史物体,回调事件被触发!",6);
+            LOG.log("有活跃物体转换为了历史物体,回调事件被触发!", 6);
+            LOG.log(string.Format("图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum), 6);
+
             if (e.Actives.Where(o => o.StateCode == 7).Count() > 0)
             {
                 stopwatch.Restart();
@@ -291,92 +411,34 @@ namespace CCDCount.DLL
                 stopwatch.Stop();
                 _ShuLiState = true;
             }
+            //往数组中计数
+            ushort result = new ushort();
+            // 事件处理逻辑
             foreach (ActiveObjectClass oneActive in e.Actives)
             {
-                LOG.log(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4}",
-                    oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode), 6);
+                Console.WriteLine(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}",
+                    oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO));
+                LOG.log(string.Format("输出当前颗粒信息,开始行:{0},结束行:{1},开始时间:{2}结束时间:{3},颗粒状态:{4},通道数:{5}",
+                    oneActive.StartLine, oneActive.LastSeenLine, oneActive.StartCheckTime.ToString("O"), oneActive.EndCheckTime.ToString("O"), oneActive.StateCode, oneActive.ChannelNO), 6);
 
-            }
-           // 事件处理逻辑
-            float step = -1;
-            float[] floats  = new float[9];
-            zmcauxClass.GetMessageFromVar("countStep", ref step);
-            LOG.log(string.Format("{0}:countStep = {1}", "MainThreadClass-Worker_OneGrainCompleted", step),6);
-            if (step < 1 || step>3)
-            {
-                zmcauxClass.GetMessageFromArray("CCD_DATA4", ref floats, 0, 9);
-            }
-            else
-            {
-                switch (step)
+                if (oneActive.StateCode == 0 && oneActive.ChannelNO != -1)
                 {
-                    case 1:
-                        zmcauxClass.GetMessageFromArray("CCD_DATA1", ref floats, 0, 9);
-                        break;
-                    case 2:
-                        zmcauxClass.GetMessageFromArray("CCD_DATA2", ref floats, 0, 9);
-                        break;
-                    case 3:
-                        zmcauxClass.GetMessageFromArray("CCD_DATA3", ref floats, 0, 9);
-                        break;
-                }
-            }
-            LOG.log("读取轴卡结果数据:" + floats[0] + " " + floats[1] + " " + floats[2] + " " + floats[3] + " " + floats[4] + " " + floats[5] + " " + floats[6] + " " + floats[7] + " " + floats[8],6);
-            foreach (ActiveObjectClass oneActive in e.Actives)
-            {
-                if (oneActive.StateCode != 0)
-                {
-                    floats[8] += 1;
+                    //单通道合格计数
+                    result |= (ushort)(1 << (oneActive.ChannelNO));
                 }
                 else
                 {
-                    if (oneActive.ChannelNO != -1)
-                        floats[oneActive.ChannelNO] += 1;
-                    else
-                        floats[8] += 1;
+                    //单通道不合格计数
+                    result |= (ushort)(1 << 8);
                 }
-
             }
-            LOG.log("写入轴卡结果数据:" + floats[0] + " " + floats[1] + " " + floats[2] + " " + floats[3] + " " + floats[4] + " " + floats[5] + " " + floats[6] + " " + floats[7] + " " + floats[8],6);
-            if  (step < 1 || step>3)
+            LOG.log("当前待发送队列数量:" + SendQueue.Count, 6);
+            if(IsSend)
             {
-                zmcauxClass.SetMessageToArray("CCD_DATA4", floats, 0, 9);
+                SendQueue.Enqueue(result);
             }
-            else
-            {
-                switch (step)
-                {
-                    case 1:
-                        zmcauxClass.SetMessageToArray("CCD_DATA1", floats, 0, 9);
-                        break;
-                    case 2:
-                        zmcauxClass.SetMessageToArray("CCD_DATA2", floats, 0, 9);
-                        break;
-                    case 3:
-                        zmcauxClass.SetMessageToArray("CCD_DATA3", floats, 0, 9);
-                        break;
-                }
-            }
-            //OnOneGrain(e.Actives);
-        }
-
-        /// <summary>
-        /// 装瓶逻辑
-        /// </summary>
-        private void BottLogicFunction()
-        { 
-
         }
 
-        /// <summary>
-        /// 对外通知事件
-        /// </summary>
-        private void OnOneGrain(List<ActiveObjectClass> activeObject)
-        {
-            ActiveObjectEventArgsClass activeObjectEventArgs = new ActiveObjectEventArgsClass(activeObject);
-            // 触发事件
-            WorkerToFrom?.Invoke(this, activeObjectEventArgs);
-        }
         #endregion
 
         #region 线程方法
@@ -406,7 +468,7 @@ namespace CCDCount.DLL
             }
             catch (Exception ex)
             {
-                LOG.error("Start thread failed!, " + ex.Message);
+                FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
                 throw;
             }
         }
@@ -423,7 +485,7 @@ namespace CCDCount.DLL
             {
                 if (stopwatch.ElapsedMilliseconds > 1000)
                 {
-                    Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum);
+                    //Console.WriteLine("交换线程-图像处理实例中的待识别图像缓存队列长度{0}", shuLiClass.ImageNum);
                     GC.Collect();
                     stopwatch.Restart();
                 }
@@ -431,6 +493,11 @@ namespace CCDCount.DLL
                 bool result = cameraClass.GetOnceImage(out IFramedata);
                 if (result)
                 {
+                    //Debug模式,不进行图像处理
+                    if (IsDebug)
+                    {
+                        continue;
+                    }
                     if (IFramedata == null)
                         continue;
                     shuLiClass.SetOnceIdentifyImageData(IFramedata.Image);
@@ -441,6 +508,101 @@ namespace CCDCount.DLL
             }
             stopwatch.Stop();
         }
+
+        /// <summary>
+        /// 启动发送消息线程
+        /// </summary>
+        private void StartSendBottLogicMessageThread()
+        {
+            try
+            {
+                if(!IsConnectModbus) return;
+                //zmcauxClass.OpenZmcauxCard();
+
+                timeBeginPeriod(1); // 设置为1ms精度
+                IsSend = true;
+                SendBottLogicMessageThread = new Thread(SendBottLogicMessageProcess);
+                SendBottLogicMessageThread.Start();
+            }
+            catch (Exception ex)
+            {
+                FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
+                throw;
+            }
+        }
+        /// <summary>
+        /// 停止发送消息线程
+        /// </summary>
+        private void StopSendBottLogicMessageThread()
+        {
+            try
+            {
+                // 标志位设为false
+                IsSend = false;
+                if (SendBottLogicMessageThread != null && SendBottLogicMessageThread.IsAlive)
+                    SendBottLogicMessageThread.Join();
+                if (modbusTcpClient != null) modbusTcpClient.Disconnect();
+            }
+            catch (Exception ex)
+            {
+                FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
+                throw;
+            }
+        }
+
+        /// <summary>
+        /// 信息发送线程
+        /// </summary>
+        private void SendBottLogicMessageProcess()
+        {
+            //获取数据
+            ushort sendMessage = 0;
+            bool AllowTransfer = false;
+            bool TransferDone = false;
+            Stopwatch sw = Stopwatch.StartNew();
+            while (IsSend)
+            {
+                //LOG.log("进入线程", 6);
+                sw.Restart();
+                sendMessage = new ushort();
+                //读取装瓶状态
+                AllowTransfer = false;
+                TransferDone = false;
+                bool[] ReadResult = modbusTcpClient.ReadCoilsRegister(slaveId: 1, startAddress: 11, numRegisters: 2);
+                if (ReadResult == null)
+                {
+                    continue;
+                }
+                AllowTransfer = ReadResult[1];
+                TransferDone = ReadResult[0];
+                //LOG.log(string.Format("读取值:AllowTransfer[0]:{0},TransferDone[1]:{1}", AllowTransfer, TransferDone), 6);
+                //当允许写入且处于未写入的状态时
+                if (AllowTransfer && !TransferDone)
+                {
+                    if (SendQueue.Count() > 0)
+                    {
+                        if (!SendQueue.TryDequeue(out sendMessage))
+                        {
+                            FaultLog.RecordErrorMessage("MainThreadClass-SendBottLogicMessageProcess-SendQueue.TryDequeue failed!");
+                        }
+                    }
+                    if (sendMessage != 0)
+                    {
+                        //写入数据
+                        modbusTcpClient.WriteSingleRegister(slaveId: 1, registerAddress: 100, value: sendMessage);
+                        modbusTcpClient.WriteCoilsRegister(slaveId: 1, CoilsAddress: 11, values: true);
+                    }
+                    sw.Stop();
+                    FaultLog.RecordLogMessage(string.Format("sendMessage[1]:{0},此次写值耗时:{1}", sendMessage, sw.Elapsed),1);
+                }
+                Thread.Sleep(1);
+            }
+        }
+        #endregion
+
+        #region 外部函数
+        [DllImport("winmm.dll")]
+        static extern uint timeBeginPeriod(uint period);
         #endregion
     }
 }

+ 6 - 6
TestWork.DLL/MechanicalControlClass.cs

@@ -54,7 +54,7 @@ namespace CCDCount.DLL
                 g_uRet = CEtherCAT_DLL.CS_ECAT_Master_Initial(nCardNo);
                 if (g_uRet != CEtherCAT_DLL_Err.ERR_ECAT_NO_ERROR)
                 {
-                    LOG.error("_ECAT_Master_Initial, ErrorCode = " + g_uRet.ToString());
+                    FaultLog.RecordErrorMessage("_ECAT_Master_Initial, ErrorCode = " + g_uRet.ToString());
                     g_uESCCardNoList[nSeq] = 99;
                 }
                 else
@@ -86,7 +86,7 @@ namespace CCDCount.DLL
 
             if (g_uRet != CEtherCAT_DLL_Err.ERR_ECAT_NO_ERROR)
             {
-                LOG.error("_ECAT_Slave_Motion_Set_Svon, Error Code = " + g_uRet.ToString());
+                FaultLog.RecordErrorMessage("_ECAT_Slave_Motion_Set_Svon, Error Code = " + g_uRet.ToString());
             }
         }
 
@@ -149,13 +149,13 @@ namespace CCDCount.DLL
 
             if (g_uRet != CEtherCAT_DLL_Err.ERR_ECAT_NO_ERROR)
             {
-                LOG.error("CS_ECAT_Master_Open, rt =" + g_uRet.ToString());
+                FaultLog.RecordErrorMessage("CS_ECAT_Master_Open, rt =" + g_uRet.ToString());
             }
             else
             {
                 if (g_nESCExistCards == 0)
                 {
-                    LOG.error("No EtherCat can be found!");
+                    FaultLog.RecordErrorMessage("No EtherCat can be found!");
                 }
                 else
                 {
@@ -175,13 +175,13 @@ namespace CCDCount.DLL
 
             if (g_uRet != CEtherCAT_DLL_Err.ERR_ECAT_NO_ERROR)
             {
-                LOG.error("_ECAT_Master_Get_SlaveNum, ErrorCode = " + g_uRet.ToString());
+                FaultLog.RecordErrorMessage("_ECAT_Master_Get_SlaveNum, ErrorCode = " + g_uRet.ToString());
             }
             else
             {
                 if (uSlaveNum == 0)
                 {
-                    LOG.error("Card NO: " + g_uESCCardNo.ToString() + " No slave found!");
+                    FaultLog.RecordErrorMessage("Card NO: " + g_uESCCardNo.ToString() + " No slave found!");
                 }
                 else
                 {

+ 41 - 26
TestWork.DLL/ShuLiClass.cs

@@ -21,13 +21,13 @@ namespace CCDCount.DLL
         public event EventHandler<ActiveObjectEventArgsClass> WorkCompleted;
         private List<ActiveObjectClass> activeObjects = new List<ActiveObjectClass>(); // 当前跟踪中的物体
         private List<ActiveObjectClass> historyActiveObjects = new List<ActiveObjectClass>(); // 历史物体
-        private ConcurrentQueue<byte[]> ImageBytes = new ConcurrentQueue<byte[]>(); //图像数据队列
         private ConcurrentQueue<IImage> IFrameDatas = new ConcurrentQueue<IImage>(); //图像数据队列
         private Thread IdentifyImageProcessThread = null; // 识别线程
         private bool IsIdentify = false; //线程是否开始识别的标志
         private long currentLine = 0; //行数记录
         private ShuLiConfigClass shuLiConfig = null;// 数粒参数配置文件
-        private List<int> ChannelsRoi = new List<int>();
+        public List<int> ChannelsRoi{get{ return _ChannelsRoi; }}
+        private List<int> _ChannelsRoi = new List<int>();
         private int ChannelWidth = 0;//每个区域的宽度
         private int IdentifyImageWidth = -1;
         private static readonly object _lockObj = new object(); // 专用锁对象\
@@ -64,6 +64,7 @@ namespace CCDCount.DLL
                     PandingCode = 2
                 };
             }
+            InitChannel();
         }
 
         /// <summary>
@@ -117,14 +118,6 @@ namespace CCDCount.DLL
                 return historyActiveObjects.Count();
         }
 
-        /// <summary>
-        /// 清除缓存的内存的中的历史数据
-        /// </summary>
-        public void ClearHistoryActive()
-        {
-            historyActiveObjects.Clear();
-        }
-
         /// <summary>
         /// 获取历史数据中,正常数据数量
         /// </summary>
@@ -145,6 +138,19 @@ namespace CCDCount.DLL
                 return historyActiveObjects.Where(o=>o.StateCode != 0).Count();
         }
 
+        /// <summary>
+        /// 清除历史数据
+        /// </summary>
+        /// <returns></returns>
+        public bool ClearHistoryActive()
+        {
+            lock (_lockObj)
+            {
+                historyActiveObjects.Clear();
+                return true;
+            }
+        }
+
         /// <summary>
         /// 开启识别
         /// </summary>
@@ -165,7 +171,7 @@ namespace CCDCount.DLL
             }
             catch (Exception ex)
             {
-                LOG.error("Start thread failed!, " + ex.Message);
+                FaultLog.RecordErrorMessage("Start thread failed!, " + ex.Message);
                 throw;
             }
         }
@@ -184,20 +190,11 @@ namespace CCDCount.DLL
             }
             catch (Exception ex)
             {
-                LOG.error("Stop thread failed!, " + ex.Message);
+                FaultLog.RecordErrorMessage("Stop thread failed!, " + ex.Message);
                 throw;
             }
         }
 
-        /// <summary>
-        /// 向识别队列添加一个数据
-        /// </summary>
-        /// <param name="items"></param>
-        public void SetOnceIdentifyImageData(byte[] items)
-        {
-            ImageBytes.Enqueue(items.Clone() as byte[]);
-        }
-
         /// <summary>
         /// 向识别队列添加一个数据
         /// </summary>
@@ -231,7 +228,8 @@ namespace CCDCount.DLL
         /// <param name="ImageWidth"></param>
         public void InitChannel()
         {
-            shuLiConfig.ImageWidth = IdentifyImageWidth;
+            _ChannelsRoi.Clear();
+            shuLiConfig.ImageWidth = IdentifyImageWidth==-1? shuLiConfig.ImageWidth: IdentifyImageWidth;
             if (shuLiConfig.Channel > 0)
             {
                 if (shuLiConfig.IsIdentifyRoiOpen)
@@ -244,7 +242,7 @@ namespace CCDCount.DLL
                 }
                 for (int i = 0; i < shuLiConfig.Channel; i++)
                 {
-                    ChannelsRoi.Add(ChannelWidth + i * ChannelWidth);
+                    _ChannelsRoi.Add(ChannelWidth + i * ChannelWidth);
                 }
             }
         }
@@ -259,6 +257,14 @@ namespace CCDCount.DLL
 
             return result;
         }
+
+        public int GetConfigImageWidth()
+        {
+            int result = -1;
+            if(shuLiConfig != null)
+                result = shuLiConfig.ImageWidth;
+            return result;
+        }
         #endregion
 
         #region 私有方法
@@ -273,6 +279,9 @@ namespace CCDCount.DLL
             WorkCompleted?.Invoke(this, activeObjectEventArgs);
         }
 
+        private bool IsPrintLightOnError = false;
+        private bool IsObstructedViewError = false;
+
         /// <summary>
         /// 处理单行像素数据
         /// 返回值为false的时候无活跃物体转变为历史物体
@@ -289,9 +298,14 @@ namespace CCDCount.DLL
             {
                 if (currentRegions[0].End - (currentRegions[0]).Start + 1 == imagedata.Width)
                 {
-                    LOG.error("当前行有效区域为整行,检查视野和光源");
+                    if(!IsPrintLightOnError)
+                    {
+                        FaultLog.RecordLogMessage("当前行有效区域为整行,检查视野和光源", 5);
+                        IsPrintLightOnError = true;
+                    }
                     return false;
                 }
+                IsPrintLightOnError = false;
             }
             // 步骤2:处理当前行每个区域
             for (int i = 0; i < currentRegions.Count; i++)
@@ -400,7 +414,8 @@ namespace CCDCount.DLL
                     if ((item.LastSeenLine - item.StartLine) > shuLiConfig.MAX_Idetify_Height)
                     {
                         item.StateCode = 7;
-                        LOG.error("ShuLiClass-ProcessLine:非颗粒,视野异常");
+                        FaultLog.RecordLogMessage("ShuLiClass-ProcessLine:非颗粒,视野异常",3);
+                        LOG.log(string.Format("ShuLiClass-ProcessLine:非颗粒,视野异常"), 6);
                         Console.WriteLine("ShuLiClass-ProcessLine:非颗粒,视野异常");
                     }
                     else if (shuLiConfig.PandingCode != -1)
@@ -566,7 +581,7 @@ namespace CCDCount.DLL
             }
             else
             {
-                result = ChannelsRoi[StartChannel] - activeObject.MinStartCol > activeObject.MaxEndCol - ChannelsRoi[StartChannel]? StartChannel: EndChannel;
+                result = _ChannelsRoi[StartChannel] - activeObject.MinStartCol > activeObject.MaxEndCol - _ChannelsRoi[StartChannel]? StartChannel: EndChannel;
             }
             return result;
         }

+ 104 - 0
TestWork.DLL/SqlDataClass/ErrorMesSqliteDataClass.cs

@@ -0,0 +1,104 @@
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Data.SQLite;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.DLL.SqlDataClass
+{
+    public class ErrorMesSqliteDataClass
+    {
+        private readonly string _dbPath;
+
+        public ErrorMesSqliteDataClass(string dbPath)
+        {
+            _dbPath = dbPath;
+
+            // 1. 获取文件夹路径
+            string directoryPath = Path.GetDirectoryName(dbPath);
+
+            // 2. 检查文件夹是否存在
+            if (!Directory.Exists(directoryPath))
+            {
+                // 创建文件夹
+                Directory.CreateDirectory(directoryPath);
+            }
+            InitializeDatabase();
+        }
+
+        // 初始化数据库和表
+        private void InitializeDatabase()
+        {
+            if (!File.Exists(_dbPath))
+            {
+                SQLiteConnection.CreateFile(_dbPath);
+            }
+
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string createTableSql = @"
+                    CREATE TABLE IF NOT EXISTS ErrMessage (
+                        Id INTEGER PRIMARY KEY AUTOINCREMENT,
+                        Number INTEGER NOT NULL,
+                        Category TEXT NOT NULL,
+                        MessageType TEXT NOT NULL,
+                        Message TEXT NOT NULL,
+                        DateTime TEXT NOT NULL,
+                        UserID INTEGER NOT NULL
+                )";
+                new SQLiteCommand(createTableSql, conn).ExecuteNonQuery();
+            }
+        }
+
+        // 插入数据
+        public void InsertErrMessage(ErroeMesDataModelClass Message)
+        {
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "INSERT INTO ErrMessage (Number, Category, MessageType,Message,DateTime,UserID) VALUES (@Number, @Category, @MessageType,@Message, @DateTime, @UserID)";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@Number", Message.Number);
+                cmd.Parameters.AddWithValue("@Category", Message.Category);
+                cmd.Parameters.AddWithValue("@MessageType", Message.MessageType);
+                cmd.Parameters.AddWithValue("@Message", Message.Message);
+                cmd.Parameters.AddWithValue("@DateTime", Message.DateTime.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 格式化为字符串
+                cmd.Parameters.AddWithValue("@UserID", Message.UserID);
+                cmd.ExecuteNonQuery();
+            }
+        }
+
+        // 查询所有数据
+        public List<ErroeMesDataModelClass> GetAllErrMessage()
+        {
+            var persons = new List<ErroeMesDataModelClass>();
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "SELECT * FROM ErrMessage";
+                var cmd = new SQLiteCommand(sql, conn);
+                using (SQLiteDataReader reader = cmd.ExecuteReader())
+                {
+                    while (reader.Read())
+                    {
+                        persons.Add(new ErroeMesDataModelClass
+                        {
+                            Number = Convert.ToInt32(reader["Number"]),
+                            Category = reader["Category"].ToString(),
+                            MessageType = reader["MessageType"].ToString(),
+                            Message = reader["Message"].ToString(),
+                            UserID = Convert.ToInt32(reader["UserID"]),
+                            // 解析时间字符串
+                            DateTime = DateTime.Parse(reader["DateTime"].ToString())
+                        });
+                    }
+                }
+            }
+            return persons;
+        }
+    }
+}

+ 268 - 0
TestWork.DLL/SqlDataClass/UserMessSqliteDataClass.cs

@@ -0,0 +1,268 @@
+using CCDCount.MODEL.SqlDataModel;
+using System;
+using System.Collections.Generic;
+using System.Data.SQLite;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.DLL.SqlDataClass
+{
+    public class UserMessSqliteDataClass
+    {
+        private readonly string _dbPath;
+
+        //构建方法,根绝地址初始化数据库
+        public UserMessSqliteDataClass(string dbPath)
+        {
+            _dbPath = dbPath;
+
+            // 1. 获取文件夹路径
+            string directoryPath = Path.GetDirectoryName(dbPath);
+
+            // 2. 检查文件夹是否存在
+            if (!Directory.Exists(directoryPath))
+            {
+                // 创建文件夹
+                Directory.CreateDirectory(directoryPath);
+            }
+            InitializeDatabase();
+        }
+
+        // 初始化数据库和表
+        private void InitializeDatabase()
+        {
+            if (!File.Exists(_dbPath))
+            {
+                SQLiteConnection.CreateFile(_dbPath);
+            }
+
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string createTableSql = @"
+                    CREATE TABLE IF NOT EXISTS UserMessage (
+                        Id INTEGER PRIMARY KEY AUTOINCREMENT,
+                        UserName TEXT NOT NULL,
+                        PassWord TEXT NOT NULL,
+                        UserMes TEXT NOT NULL,
+                        DateTime TEXT NOT NULL,
+                        IsDelete INTEGER CHECK (IsDelete IN (0, 1)),
+                        IsAdmin INTEGER CHECK (IsAdmin IN (0, 1))
+                )";
+                new SQLiteCommand(createTableSql, conn).ExecuteNonQuery();
+            }
+        }
+
+        // 插入数据
+        public int InsertUserMessage(UserMesDataModelClass Message)
+        {
+            int result = -1;
+            if(GetUserMessageForName(Message.UserName).Count>0)
+            {
+                result = 2;
+                return result;
+            }
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "INSERT INTO UserMessage (UserName, PassWord,UserMes,IsDelete,IsAdmin,DateTime) VALUES (@UserName, @PassWord,@UserMes,@IsDelete,@IsAdmin,@DateTime)";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@UserName", Message.UserName);
+                cmd.Parameters.AddWithValue("@PassWord", HashPassword(Message.PassWord));
+                cmd.Parameters.AddWithValue("@UserMes", Message.UserMes);
+                cmd.Parameters.AddWithValue("@IsDelete", Message.IsDelete == true ? 1 : 0);
+                cmd.Parameters.AddWithValue("@IsAdmin", Message.IsAdmin == true ? 1 : 0);
+                cmd.Parameters.AddWithValue("@DateTime", Message.DateTime.ToString("yyyy-MM-dd HH:mm:ss.fff")); // 格式化为字符串
+                cmd.ExecuteNonQuery();
+                result = 0;
+            }
+            return result;
+        }
+
+        // 查询所有数据
+        public List<UserMesDataModelClass> GetAllUserMessage()
+        {
+            var persons = new List<UserMesDataModelClass>();
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "SELECT * FROM UserMessage WHERE IsDelete=0";
+                var cmd = new SQLiteCommand(sql, conn);
+                using (SQLiteDataReader reader = cmd.ExecuteReader())
+                {
+                    while (reader.Read())
+                    {
+                        persons.Add(new UserMesDataModelClass
+                        {
+                            Id = Convert.ToInt32(reader["Id"]),
+                            UserName = reader["UserName"].ToString(),
+                            PassWord = reader["PassWord"].ToString(),
+                            UserMes = reader["UserMes"].ToString(),
+                            // 解析时间字符串
+                            DateTime = DateTime.Parse(reader["DateTime"].ToString()),
+                            IsAdmin = Convert.ToInt32(reader["IsAdmin"]) == 1 ? true : false,
+                            IsDelete = Convert.ToInt32(reader["IsDelete"]) == 1 ? true : false
+                        });
+                    }
+                }
+            }
+            return persons;
+        }
+
+        // 查询对应用户名的所有信息
+        public List<UserMesDataModelClass> GetUserMessageForName(string UserName)
+        {
+            var persons = new List<UserMesDataModelClass>();
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "SELECT * FROM UserMessage WHERE UserName = @UserName AND IsDelete = 0";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@UserName", UserName);
+                using (SQLiteDataReader reader = cmd.ExecuteReader())
+                {
+                    while (reader.Read())
+                    {
+                        persons.Add(new UserMesDataModelClass
+                        {
+                            Id = Convert.ToInt32(reader["Id"]),
+                            UserName = reader["UserName"].ToString(),
+                            PassWord = reader["PassWord"].ToString(),
+                            UserMes = reader["UserMes"].ToString(),
+                            // 解析时间字符串
+                            DateTime = DateTime.Parse(reader["DateTime"].ToString()),
+                            IsAdmin = Convert.ToInt32(reader["IsAdmin"]) == 1 ? true : false,
+                            IsDelete = Convert.ToInt32(reader["IsDelete"]) == 1 ? true : false
+                        });
+                    }
+                }
+            }
+            return persons;
+        }
+
+        // 查询对应用户ID的所有信息
+        public List<UserMesDataModelClass> GetUserMessageForId(int Id)
+        {
+            var persons = new List<UserMesDataModelClass>();
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "SELECT * FROM UserMessage WHERE Id = @Id AND IsDelete = 0";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@Id", Id);
+                using (SQLiteDataReader reader = cmd.ExecuteReader())
+                {
+                    while (reader.Read())
+                    {
+                        persons.Add(new UserMesDataModelClass
+                        {
+                            Id = Convert.ToInt32(reader["Id"]),
+                            UserName = reader["UserName"].ToString(),
+                            PassWord = reader["PassWord"].ToString(),
+                            UserMes = reader["UserMes"].ToString(),
+                            // 解析时间字符串
+                            DateTime = DateTime.Parse(reader["DateTime"].ToString()),
+                            IsAdmin = Convert.ToInt32(reader["IsAdmin"]) == 1 ? true : false,
+                            IsDelete = Convert.ToInt32(reader["IsDelete"]) == 1 ? true : false
+                        });
+                    }
+                }
+            }
+            return persons;
+        }
+
+        //查询用户名的登录信息是否正确
+        public bool CheckUserLogin(string UserName, string PassWord)
+        {
+            return GetAllUserMessage().Any(x => x.UserName == UserName && x.PassWord == HashPassword(PassWord));
+        }
+
+        //修改密码(使用ID)
+        public bool ChangePassWord(int Id, string OldPassWord, string NewPassWord)
+        {
+            bool result = false;
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "UPDATE UserMessage SET PassWord = @PassWord WHERE Id = @Id AND IsDelete = 0";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@PassWord", HashPassword(NewPassWord));
+                cmd.Parameters.AddWithValue("@Id", Id);
+                cmd.ExecuteNonQuery();
+                result = true;
+            }
+            return result;
+        }
+
+        public bool ChangeUserMessage(int Id,UserMesDataModelClass Message)
+        {
+            bool result = false;
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "UPDATE UserMessage SET UserName = @UserName,PassWord = @PassWord,UserMes = @UserMes,IsAdmin = @IsAdmin WHERE Id = @Id AND IsDelete = 0";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@UserName", Message.UserName);
+                cmd.Parameters.AddWithValue("@PassWord", HashPassword(Message.PassWord));
+                cmd.Parameters.AddWithValue("@UserMes", Message.UserMes);
+                cmd.Parameters.AddWithValue("@Id", Id);
+                cmd.Parameters.AddWithValue("@IsAdmin", Message.IsAdmin);
+                cmd.ExecuteNonQuery();
+                result = true;
+            }
+            return result;
+        }
+        
+        // 重置密码
+        public bool ResetPassWord(int Id)
+        {
+            bool result = false;
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "UPDATE UserMessage SET PassWord = @PassWord WHERE Id = @Id AND IsDelete = 0";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@PassWord", HashPassword("123456"));
+                cmd.Parameters.AddWithValue("@Id", Id);
+                cmd.ExecuteNonQuery();
+                result = true;
+            }
+            return result;
+        }
+
+        // 删除用户信息
+        public bool DeleteUserMessage(int Id)
+        {
+            bool result = false;
+            using (var conn = new SQLiteConnection($"Data Source={_dbPath};Version=3;"))
+            {
+                conn.Open();
+                string sql = "UPDATE UserMessage SET IsDelete = 1 WHERE Id = @Id";
+                var cmd = new SQLiteCommand(sql, conn);
+                cmd.Parameters.AddWithValue("@Id", Id);
+                cmd.ExecuteNonQuery();
+                result = true;
+            }
+            return result;
+        }
+
+
+        // Hash密码加密
+        public string HashPassword(string password)
+        {
+            using (SHA256 sha256 = SHA256.Create())
+            {
+                byte[] bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(password));
+                StringBuilder builder = new StringBuilder();
+                for (int i = 0; i < bytes.Length; i++)
+                {
+                    builder.Append(bytes[i].ToString("x2"));
+                }
+                return builder.ToString();
+            }
+        }
+    }
+}

+ 175 - 0
TestWork.DLL/Tools/ModbusClass.cs

@@ -0,0 +1,175 @@
+using LogClass;
+using NModbus;
+using System;
+using System.Net.Sockets;
+
+namespace CCDCount.DLL.Tools
+{
+    public class ModbusTcpClient
+    {
+        private TcpClient _tcpClient;
+        private IModbusMaster _modbusMaster;
+
+        public bool IsTcpClientConnected()
+        {
+            if (_tcpClient == null || _tcpClient.Client == null)
+                return false;
+
+            try
+            {
+                Socket socket = _tcpClient.Client;
+                bool isReadable = socket.Poll(0, SelectMode.SelectRead);
+                bool hasNoData = (socket.Available == 0);
+
+                // 可读且无数据 = 连接已断开
+                return !(isReadable && hasNoData);
+            }
+            catch (SocketException) { return false; }
+            catch (ObjectDisposedException) { return false; }
+        }
+
+        /// <summary>
+        /// 连接 Modbus TCP 服务器
+        /// </summary>
+        /// <param name="ipAddress"></param>
+        /// <param name="port"></param>
+        /// <returns></returns>
+        public bool Connect(string ipAddress, int port = 502)
+        {
+            try
+            {
+                _tcpClient = new TcpClient(ipAddress, port)
+                {
+                    SendTimeout = 2000,
+                    ReceiveTimeout = 2000
+                };
+                // 使用 ModbusFactory 创建 Master(新版本 API)
+                var factory = new ModbusFactory();
+                _modbusMaster = factory.CreateMaster(_tcpClient);
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"连接失败: {ex.Message}");
+                return false;
+            }
+        }
+
+        /// <summary>
+        /// 断开连接
+        /// </summary>
+        public void Disconnect()
+        {
+            _modbusMaster?.Dispose();
+            _tcpClient?.Close();
+        }
+        /// <summary>
+        /// 读取线圈(功能码01)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="numRegisters"></param>
+        /// <returns></returns>
+        /// <exception cref="InvalidOperationException"></exception>
+        public bool[] ReadCoilsRegister(byte slaveId, ushort startAddress, ushort numRegisters)
+        {
+            if (_modbusMaster == null) throw new InvalidOperationException("未连接到服务器");
+            try
+            {
+                return _modbusMaster.ReadCoils(slaveId, startAddress, numRegisters);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取线圈失败: {ex.Message}");
+                FaultLog.RecordErrorMessage($"MainThreadClass-ReadCoilsRegister-ReadCoilsRegister failed:{ex.Message}");
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// 读取保持寄存器(功能码03)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="numRegisters"></param>
+        /// <returns></returns>
+        /// <exception cref="InvalidOperationException"></exception>
+        public ushort[] ReadHoldingRegisters(byte slaveId, ushort startAddress, ushort numRegisters)
+        {
+            if (_modbusMaster == null) throw new InvalidOperationException("未连接到服务器");
+            try
+            {
+                return _modbusMaster.ReadHoldingRegisters(slaveId, startAddress, numRegisters);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"读取保持寄存器失败: {ex.Message}");
+                FaultLog.RecordErrorMessage($"MainThreadClass-ReadHoldingRegisters-ReadHoldingRegisters failed:{ex.Message}");
+                return null;
+            }
+        }
+        /// <summary>
+        /// 写入线圈(功能码05)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="CoilsAddress"></param>
+        /// <param name="values"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public void WriteCoilsRegister(byte slaveId, ushort CoilsAddress, bool values)
+        {
+            if (_modbusMaster == null) throw new InvalidOperationException("未连接到服务器");
+            try
+            {
+                _modbusMaster.WriteSingleCoil(slaveId, CoilsAddress, values);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入线圈失败: {ex.Message}");
+                FaultLog.RecordErrorMessage($"MainThreadClass-WriteCoilsRegister-WriteCoilsRegister failed:{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 写入单个寄存器(功能码06)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="registerAddress"></param>
+        /// <param name="value"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public void WriteSingleRegister(byte slaveId, ushort registerAddress, ushort value)
+        {
+
+            if (_modbusMaster == null) throw new InvalidOperationException("未连接到服务器");
+            try
+            {
+                _modbusMaster.WriteSingleRegister(slaveId, registerAddress, value);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入单个寄存器失败: {ex.Message}");
+                FaultLog.RecordErrorMessage($"MainThreadClass-WriteSingleRegister-WriteSingleRegister failed:{ex.Message}");
+            }
+        }
+
+        /// <summary>
+        /// 写入多个寄存器(功能码16)
+        /// </summary>
+        /// <param name="slaveId"></param>
+        /// <param name="startAddress"></param>
+        /// <param name="values"></param>
+        /// <exception cref="InvalidOperationException"></exception>
+        public void WriteMultipleRegisters(byte slaveId, ushort startAddress, ushort[] values)
+        {
+            if (_modbusMaster == null) throw new InvalidOperationException("未连接到服务器");
+            try
+            {
+                _modbusMaster.WriteMultipleRegisters(slaveId, startAddress, values);
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine($"写入多个寄存器失败: {ex.Message}");
+                FaultLog.RecordErrorMessage($"MainThreadClass-WriteMultipleRegisters-WriteMultipleRegisters failed:{ex.Message}");
+            }
+        }
+    }
+}

+ 40 - 0
TestWork.DLL/Tools/SystemMonitorClass.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Diagnostics;
+using System.Threading;
+
+public class SystemMonitor
+{
+    private readonly PerformanceCounter _cpuCounter;
+    private readonly PerformanceCounter _ramCounter;
+    Stopwatch stopwatch = Stopwatch.StartNew();
+    private float HisCPUCounter = 0;
+
+    public SystemMonitor()
+    {
+        _cpuCounter = new PerformanceCounter(
+            "Processor", "% Processor Time", "_Total");
+
+        _ramCounter = new PerformanceCounter(
+            "Memory", "Available MBytes");
+    }
+
+    public float GetCpuUsage()
+    {
+        stopwatch.Stop();
+        if (stopwatch.ElapsedMilliseconds > 1000)
+        {
+            stopwatch.Restart();
+            HisCPUCounter = _cpuCounter.NextValue();
+        }
+        else
+        {
+            stopwatch.Start();
+        }
+        return HisCPUCounter;
+    }
+
+    public float GetAvailableMemory()
+    {
+        return _ramCounter.NextValue();
+    }
+}

+ 16 - 0
TestWork.DLL/app.config

@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <configuration>
+  <configSections>
+    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
+    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
+  </configSections>
   <runtime>
     <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
       <dependentAssembly>
@@ -8,4 +12,16 @@
       </dependentAssembly>
     </assemblyBinding>
   </runtime>
+  <entityFramework>
+    <providers>
+      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
+      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
+    </providers>
+  </entityFramework>
+  <system.data>
+    <DbProviderFactories>
+      <remove invariant="System.Data.SQLite.EF6" />
+      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
+    <remove invariant="System.Data.SQLite" /><add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" /></DbProviderFactories>
+  </system.data>
 </configuration>

+ 7 - 0
TestWork.DLL/packages.config

@@ -1,10 +1,17 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
   <package id="CsvHelper" version="33.0.1" targetFramework="net48" />
+  <package id="EntityFramework" version="6.4.4" targetFramework="net48" />
   <package id="Microsoft.Bcl.AsyncInterfaces" version="8.0.0" targetFramework="net48" />
   <package id="Microsoft.Bcl.HashCode" version="1.1.1" targetFramework="net48" />
   <package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
+  <package id="NModbus" version="3.0.81" targetFramework="net48" />
+  <package id="Stub.System.Data.SQLite.Core.NetFramework" version="1.0.119.0" targetFramework="net48" />
   <package id="System.Buffers" version="4.4.0" targetFramework="net48" />
+  <package id="System.Data.SQLite" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.Core" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.EF6" version="1.0.119.0" targetFramework="net48" />
+  <package id="System.Data.SQLite.Linq" version="1.0.119.0" targetFramework="net48" />
   <package id="System.Memory" version="4.5.0" targetFramework="net48" />
   <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net48" />
   <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net48" />

+ 3 - 0
TestWork.MODEL/CCDCount.MODEL.csproj

@@ -45,10 +45,13 @@
     <Compile Include="CameraClass\CameraImageSizeClass.cs" />
     <Compile Include="CameraClass\CameraInfoClass.cs" />
     <Compile Include="ConfigModel\CamerasConfig.cs" />
+    <Compile Include="ConfigModel\SaveConfigModel.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ShuLiClass\ActiveObjectClass.cs" />
     <Compile Include="ShuLiClass\ActiveObjectEventArgsClass.cs" />
     <Compile Include="ConfigModel\ShuLiConfigClass.cs" />
+    <Compile Include="SqlDataModel\ErroeMesDataModelClass.cs" />
+    <Compile Include="SqlDataModel\UserMesDataModelClass.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="BottingClass\" />

+ 15 - 0
TestWork.MODEL/ConfigModel/SaveConfigModel.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.MODEL.ConfigModel
+{
+    public class SaveConfigModel
+    {
+        public ShuLiConfigClass ShuLiConfigClass { get; set; }
+
+        public CameraConfig CameraConfig { get; set; }
+    }
+}

+ 40 - 0
TestWork.MODEL/SqlDataModel/ErroeMesDataModelClass.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.MODEL.SqlDataModel
+{
+    public class ErroeMesDataModelClass
+    {
+        /// <summary>
+        /// 主键
+        /// </summary>
+        public int ID { get; set; }
+        /// <summary>
+        /// 错误编号
+        /// </summary>
+        public int Number { get; set; }
+        /// <summary>
+        /// 信息类别
+        /// </summary>
+        public string Category { get; set; }
+        /// <summary>
+        /// 信息类型
+        /// </summary>
+        public string MessageType { get; set; }
+        /// <summary>
+        /// 错误信息
+        /// </summary>
+        public string Message { get; set; }
+        /// <summary>
+        /// 记录时间
+        /// </summary>
+        public DateTime DateTime { get; set; }
+        /// <summary>
+        /// 用户ID
+        /// </summary>
+        public int UserID { get; set; }
+    }
+}

+ 19 - 0
TestWork.MODEL/SqlDataModel/UserMesDataModelClass.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace CCDCount.MODEL.SqlDataModel
+{
+    public class UserMesDataModelClass
+    {
+        public int Id { get; set;}
+        public string UserName {  get; set;}
+        public string PassWord {  get; set;}
+        public string UserMes {  get; set;}
+        public DateTime DateTime {  get; set;}
+        public bool IsDelete { get; set;}
+        public bool IsAdmin { get; set;}
+    }
+}

+ 2 - 0
TestWork/CCDCount.csproj

@@ -76,6 +76,7 @@
       <SpecificVersion>False</SpecificVersion>
       <HintPath>..\TestWork.DLL\DLL\MvCameraControl.Net.dll</HintPath>
     </Reference>
+    <Reference Include="PresentationCore" />
     <Reference Include="System" />
     <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
@@ -138,6 +139,7 @@
     </Compile>
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ShowBindingClass.cs" />
     <EmbeddedResource Include="Forms\DataShowForm.resx">
       <DependentUpon>DataShowForm.cs</DependentUpon>
     </EmbeddedResource>

+ 6 - 20
TestWork/Forms/MainForm.cs

@@ -1,4 +1,5 @@
 using CCDCount.DLL;
+using CCDCount.DLL.Tools;
 using CCDCount.MODEL.ConfigModel;
 using CCDCount.MODEL.ShuLiClass;
 using LogClass;
@@ -27,6 +28,7 @@ namespace CCDCount.Forms
         #region 实例
         //主线程实例队列
         public List<MainThreadClass> LsMainThread = new List<MainThreadClass>();
+        public ModbusTcpClient modbusTcpClient = new ModbusTcpClient();
 
         #endregion
 
@@ -37,7 +39,9 @@ namespace CCDCount.Forms
         public MainForm()
         {
             InitializeComponent();
-            if(File.Exists(".\\Config\\CCDCountConfig.xml"))
+            //modbusTcpClient.Connect("192.168.1.88");
+            modbusTcpClient.Connect("127.0.0.1");
+            if (File.Exists(".\\Config\\CCDCountConfig.xml"))
             {
                 Configs = XmlStorage.DeserializeFromXml<List<(CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue)>>(".\\Config\\CCDCountConfig.xml");
             }
@@ -209,6 +213,7 @@ namespace CCDCount.Forms
                 //判断是否添加线程
                 if (!LsMainThread[i].IsOpenLoadThread)
                     return;
+                LsMainThread[i].SetModbusClient(modbusTcpClient);
                 //启动单相机实例的全部线程
                 if(!LsMainThread[i].StartMianThread(Configs.Select(o => o.CameraConfigValue).ToList().Where(o=>o.CameraSNNum == LsMainThread[i].ThisCameraSN).First()))
                 {
@@ -216,7 +221,6 @@ namespace CCDCount.Forms
                     MessageBox.Show(LsMainThread[i].ThisCameraDevice + "_" + LsMainThread[i].ThisCameraSN + "启动失败");
                     return;
                 }
-                LsMainThread[i].WorkerToFrom +=  Worker_MianThreadToFrom;
             }
         }
 
@@ -232,23 +236,5 @@ namespace CCDCount.Forms
         }
 
         #endregion
-
-        #region  主界面回调事件
-        /// <summary>
-        /// 通知主界面回调的事件
-        /// </summary>
-        /// <param name="sender"></param>
-        /// <param name="e"></param>
-        private void Worker_MianThreadToFrom(object sender, ActiveObjectEventArgsClass e)
-        {
-            // 事件处理逻辑
-            Console.WriteLine("结果已通知到主界面!");
-
-
-            
-            //此处进行与下位机的交互(将通道数给下位机控制程序)
-            //float getvalue = 0;
-        }
-        #endregion
     }
 }

+ 75 - 76
TestWork/Forms/SettingForm.cs

@@ -21,14 +21,12 @@ namespace CCDCount.Forms
         List<MainThreadClass> LoadLsMainThread = null;
         List<MainThreadClass> NowLoadLsMianThread = new List<MainThreadClass>();
         MainThreadClass LoadMainThread  = null;
-        (CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue) NowLoadConfig = (null, null);
+        SaveConfigModel NowLoadConfig = null;
         //从外部加载的信息
-        List<(CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue)> LoadConfigs =
-        new List<(CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue)>();
+        List<SaveConfigModel> LoadConfigs = new List<SaveConfigModel>();
 
         //将要保存的信息
-        List<(CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue)> Configs =
-            new List<(CameraConfig CameraConfigValue, ShuLiConfigClass ShuLiConfigValue)>();
+        List<SaveConfigModel> Configs = new List<SaveConfigModel>();
 
         CameraClass CameraClass  =  new CameraClass();
 
@@ -56,8 +54,11 @@ namespace CCDCount.Forms
             ShuLiConfigClass shuLiConfig = null;
             for (int i = 0; i < LoadLsMainThread.Count; i++)
             {
-                LoadLsMainThread[i].GetConfigValue(out cameraConfig, out shuLiConfig);
-                LoadConfigs.Add((cameraConfig,shuLiConfig));
+                LoadLsMainThread[i].GetAllConfigValue(out cameraConfig, out shuLiConfig);
+                LoadConfigs.Add(new SaveConfigModel() { 
+                    CameraConfig = cameraConfig,
+                    ShuLiConfigClass = shuLiConfig
+                });
             }
             InitIdentifyCountCobBox();
             InitCameraCobox();
@@ -102,24 +103,22 @@ namespace CCDCount.Forms
                 //创建一个按钮,加载与此相机绑定的配置
                 if (i <= LoadConfigs.Count())
                 {
-                    string camername = LoadConfigs[i - 1].CameraConfigValue.CameraName;
+                    string camername = LoadConfigs[i - 1].CameraConfig.CameraName;
                     if(camername == string.Empty) camername = "数粒" + i;
                     ButtonText = camername;
                     //重新的CameraNo排序
-                    LoadConfigs[i-1].CameraConfigValue.CamerNo = i-1;
+                    LoadConfigs[i-1].CameraConfig.CamerNo = i-1;
                     //将从外加载的配置文件复制进当前加载的配置文件
                     Configs.Add(LoadConfigs[i-1]);
                 }
                 //没有与此相机绑定的配置文件,创建一个配置实例
                 else
                 {
-                    Configs.Add((
-                        new CameraConfig() 
-                        { 
-                            CamerNo = i-1
-                        }, 
-                        new ShuLiConfigClass()
-                    ));
+                    Configs.Add(new SaveConfigModel()
+                    {
+                        CameraConfig = new CameraConfig() { CamerNo = i - 1 },
+                        ShuLiConfigClass = new ShuLiConfigClass()
+                    });
                 }
                 if (i <= LoadLsMainThread.Count())
                 {
@@ -128,8 +127,8 @@ namespace CCDCount.Forms
                 else
                 {
                     NowLoadLsMianThread.Add(new MainThreadClass(
-                        Configs[i - 1].ShuLiConfigValue,
-                        Configs[i - 1].CameraConfigValue
+                        Configs[i - 1].ShuLiConfigClass,
+                        Configs[i - 1].CameraConfig
                     ));
                 }
                 Button button = new Button()
@@ -167,30 +166,30 @@ namespace CCDCount.Forms
             }
         }
 
-        private void LoadConfigToForm((CameraConfig,ShuLiConfigClass) LoadConfig) 
+        private void LoadConfigToForm(SaveConfigModel LoadConfig) 
         {
             if(LoadMainThread != null)
             {
                 //判断是否已经绑定相机
-                if(LoadMainThread.ThisCameraSN!=string.Empty)
+                if(LoadMainThread.cameraConfig.CameraSNNum!=string.Empty)
                 {
                     //相机选择框尝试选择绑定的相机
-                    CameraConbox.SelectedItem = LoadMainThread.ThisCameraDevice + "_" + LoadMainThread.ThisCameraSN;
+                    CameraConbox.SelectedItem = LoadMainThread.cameraConfig.DeviceName + "_" + LoadMainThread.cameraConfig.CameraSNNum;
                 }
                 if(CameraConbox.SelectedItem.ToString()!=string.Empty&&CameraConbox.SelectedItem.ToString()!= "请选择相机")
                 {
-                    ExposureTimeTbx.Text = NowLoadConfig.CameraConfigValue.ExposureTimeValue.ToString();
-                    AcquistionLineRateLabTbx.Text = NowLoadConfig.CameraConfigValue.AcquistionLineRateValue.ToString();
-                    ImageWidthTbx.Text = NowLoadConfig.CameraConfigValue.Width.ToString();
-                    ImageHeightTbx.Text = NowLoadConfig.CameraConfigValue.Height.ToString();
-                    CamUserNameTbx.Text = NowLoadConfig.CameraConfigValue.CameraName;
-                    CamOffsetXTbx.Text = NowLoadConfig.CameraConfigValue.OffsetX.ToString();
+                    ExposureTimeTbx.Text = NowLoadConfig.CameraConfig.ExposureTimeValue.ToString();
+                    AcquistionLineRateLabTbx.Text = NowLoadConfig.CameraConfig.AcquistionLineRateValue.ToString();
+                    ImageWidthTbx.Text = NowLoadConfig.CameraConfig.Width.ToString();
+                    ImageHeightTbx.Text = NowLoadConfig.CameraConfig.Height.ToString();
+                    CamUserNameTbx.Text = NowLoadConfig.CameraConfig.CameraName;
+                    CamOffsetXTbx.Text = NowLoadConfig.CameraConfig.OffsetX.ToString();
                 }
-                RegionThresholdTbx.Text =  NowLoadConfig.ShuLiConfigValue.RegionThreshold.ToString();
-                ChannelTbx.Text  =  NowLoadConfig.ShuLiConfigValue.Channel.ToString();
-                NoiseFilterTbx.Text =  NowLoadConfig.ShuLiConfigValue.NoiseFilter_Threshold.ToString();
+                RegionThresholdTbx.Text =  NowLoadConfig.ShuLiConfigClass.RegionThreshold.ToString();
+                ChannelTbx.Text  =  NowLoadConfig.ShuLiConfigClass.Channel.ToString();
+                NoiseFilterTbx.Text =  NowLoadConfig.ShuLiConfigClass.NoiseFilter_Threshold.ToString();
                 //切换识别模式
-                switch(NowLoadConfig.ShuLiConfigValue.PandingCode)
+                switch(NowLoadConfig.ShuLiConfigClass.PandingCode)
                 {
                     case -1:
                         radioButton1.Checked = true;
@@ -219,8 +218,8 @@ namespace CCDCount.Forms
             {
                 PanDuanParaPanel.Controls.Clear();
                 PanDuanParaPanel.Height = 10;
-                if(NowLoadConfig == (null,null)) return;
-                NowLoadConfig.ShuLiConfigValue.PandingCode = -1;
+                if(NowLoadConfig == null) return;
+                NowLoadConfig.ShuLiConfigClass.PandingCode = -1;
                 Configs[Nowindex] = NowLoadConfig;
             }
         }
@@ -231,7 +230,7 @@ namespace CCDCount.Forms
             {
                 PanDuanParaPanel.Controls.Clear();
                 PanDuanParaPanel.Height = 150;
-                if (NowLoadConfig == (null, null)) return;
+                if (NowLoadConfig == null) return;
                 Label label5 = new Label()
                 {
                     Text = "合格粒宽范围:",
@@ -245,7 +244,7 @@ namespace CCDCount.Forms
                     Location = new Point(10, 30),
                     Name = "MIN_OBJECT_WIDTH_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MIN_OBJECT_WIDTH.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MIN_OBJECT_WIDTH.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox1);
 
@@ -262,7 +261,7 @@ namespace CCDCount.Forms
                     Name = "MAX_OBJECT_WIDTH_TBX",
                     Location = new Point(100, 30),
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MAX_OBJECT_WIDTH.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MAX_OBJECT_WIDTH.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox2);
 
@@ -279,7 +278,7 @@ namespace CCDCount.Forms
                     Location = new Point(10, 80),
                     Name = "MIN_OBJECT_HEIGHT_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MIN_OBJECT_HEIGHT.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MIN_OBJECT_HEIGHT.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox3);
 
@@ -296,11 +295,11 @@ namespace CCDCount.Forms
                     Location = new Point(100, 80),
                     Name = "MAX_OBJECT_HEIGHT_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MAX_OBJECT_HEIGHT.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MAX_OBJECT_HEIGHT.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox4);
 
-                NowLoadConfig.ShuLiConfigValue.PandingCode = 1;
+                NowLoadConfig.ShuLiConfigClass.PandingCode = 1;
                 Configs[Nowindex] = NowLoadConfig;
             }
         }
@@ -311,7 +310,7 @@ namespace CCDCount.Forms
             {
                 PanDuanParaPanel.Controls.Clear();
                 PanDuanParaPanel.Height = 100;
-                if (NowLoadConfig == (null, null)) return;
+                if (NowLoadConfig == null) return;
                 Label label5 = new Label()
                 {
                     Text = "合格粒面积范围:",
@@ -325,7 +324,7 @@ namespace CCDCount.Forms
                     Location = new Point(100, 30),
                     Name = "MaxArea_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MaxArea.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MaxArea.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox1);
 
@@ -342,11 +341,11 @@ namespace CCDCount.Forms
                     Name = "MinArea_TBX",
                     Location = new Point(10, 30),
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MinArea.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MinArea.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox2);
 
-                NowLoadConfig.ShuLiConfigValue.PandingCode = 2;
+                NowLoadConfig.ShuLiConfigClass.PandingCode = 2;
                 Configs[Nowindex] = NowLoadConfig;
             }
         }
@@ -357,7 +356,7 @@ namespace CCDCount.Forms
             {
                 PanDuanParaPanel.Controls.Clear();
                 PanDuanParaPanel.Height = 160;
-                if (NowLoadConfig == (null, null)) return;
+                if (NowLoadConfig == null) return;
 
                 Label label5 = new Label()
                 {
@@ -372,7 +371,7 @@ namespace CCDCount.Forms
                     Location = new Point(10, 30),
                     Name = "MIN_OBJECT_WIDTH_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MIN_OBJECT_WIDTH.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MIN_OBJECT_WIDTH.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox1);
 
@@ -389,7 +388,7 @@ namespace CCDCount.Forms
                     Name = "MAX_OBJECT_WIDTH_TBX",
                     Location = new Point(100, 30),
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MAX_OBJECT_WIDTH.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MAX_OBJECT_WIDTH.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox2);
 
@@ -406,7 +405,7 @@ namespace CCDCount.Forms
                     Location = new Point(10, 80),
                     Name = "MIN_OBJECT_HEIGHT_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MIN_OBJECT_HEIGHT.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MIN_OBJECT_HEIGHT.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox3);
 
@@ -423,7 +422,7 @@ namespace CCDCount.Forms
                     Location = new Point(100, 80),
                     Name = "MAX_OBJECT_HEIGHT_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MAX_OBJECT_HEIGHT.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MAX_OBJECT_HEIGHT.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox4);
 
@@ -440,7 +439,7 @@ namespace CCDCount.Forms
                     Location = new Point(10, 130),
                     Name = "MinArea_TBX",
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MinArea.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MinArea.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox5);
 
@@ -457,11 +456,11 @@ namespace CCDCount.Forms
                     Name = "MaxArea_TBX",
                     Location = new Point(100, 130),
                     Width = 50,
-                    Text = NowLoadConfig.ShuLiConfigValue.MaxArea.ToString(),
+                    Text = NowLoadConfig.ShuLiConfigClass.MaxArea.ToString(),
                 };
                 PanDuanParaPanel.Controls.Add(textBox6);
 
-                NowLoadConfig.ShuLiConfigValue.PandingCode = 3;
+                NowLoadConfig.ShuLiConfigClass.PandingCode = 3;
                 Configs[Nowindex] = NowLoadConfig;
             }
         }
@@ -469,7 +468,7 @@ namespace CCDCount.Forms
         private void CameraConbox_SelectedIndexChanged(object sender, EventArgs e)
         {
             string ThisItemSN = CameraConbox.SelectedItem.ToString();
-            if(LoadMainThread == null || ThisItemSN == LoadMainThread.ThisCameraDevice + "_" + LoadMainThread.ThisCameraSN) return;
+            if(LoadMainThread == null || ThisItemSN == LoadMainThread.cameraConfig.DeviceName + "_" + LoadMainThread.cameraConfig.CameraSNNum) return;
             if (ThisItemSN != string.Empty && ThisItemSN != "请选择相机")
             {
                 try
@@ -487,39 +486,39 @@ namespace CCDCount.Forms
                                       "切换确认", MessageBoxButtons.YesNo);
                     if (confirmResult == DialogResult.No)
                     {
-                        CameraConbox.SelectedItem = LoadMainThread.ThisCameraDevice + "_" + LoadMainThread.ThisCameraSN;
+                        CameraConbox.SelectedItem = LoadMainThread.cameraConfig.DeviceName + "_" + LoadMainThread.cameraConfig.CameraSNNum;
                         return;
                     }
                     LoadMainThread.StopMianThread();
                 }
                 if (LoadMainThread.ReLoadCamera(ThisItemSN))
                 {
-                    LoadMainThread.GetCameraConfig(out CameraConfig CameraConfig);
+                    CameraConfig CameraConfig = LoadMainThread.GetCameraConfig();
                     if (CameraConfig != null)
                             {
                                 ExposureTimeTbx.Text = CameraConfig.ExposureTimeValue.ToString();
-                                NowLoadConfig.CameraConfigValue.ExposureTimeValue = CameraConfig.ExposureTimeValue;
+                                NowLoadConfig.CameraConfig.ExposureTimeValue = CameraConfig.ExposureTimeValue;
                                 AcquistionLineRateLabTbx.Text = CameraConfig.AcquistionLineRateValue.ToString();
-                                NowLoadConfig.CameraConfigValue.AcquistionLineRateValue = CameraConfig.AcquistionLineRateValue;
+                                NowLoadConfig.CameraConfig.AcquistionLineRateValue = CameraConfig.AcquistionLineRateValue;
                                 ImageWidthTbx.Text = CameraConfig.Width.ToString();
-                                NowLoadConfig.CameraConfigValue.Width = CameraConfig.Width;
+                                NowLoadConfig.CameraConfig.Width = CameraConfig.Width;
                                 ImageHeightTbx.Text = CameraConfig.Height.ToString();
-                                NowLoadConfig.CameraConfigValue.Height = CameraConfig.Height;
+                                NowLoadConfig.CameraConfig.Height = CameraConfig.Height;
                                 CamUserNameTbx.Text = CameraConfig.CameraName;
-                                NowLoadConfig.CameraConfigValue.CameraName = CameraConfig.CameraName;
+                                NowLoadConfig.CameraConfig.CameraName = CameraConfig.CameraName;
                                 CamOffsetXTbx.Text = CameraConfig.OffsetX.ToString();
-                                NowLoadConfig.CameraConfigValue.OffsetX = CameraConfig.OffsetX;
-                                NowLoadConfig.CameraConfigValue.CameraSNNum = CameraConfig.CameraSNNum;
-                                NowLoadConfig.CameraConfigValue.CameraName = CameraConfig.CameraName;
-                                NowLoadConfig.CameraConfigValue.DeviceName = CameraConfig.DeviceName;
-                                NowLoadConfig.ShuLiConfigValue.CameraSN = CameraConfig.CameraSNNum; 
+                                NowLoadConfig.CameraConfig.OffsetX = CameraConfig.OffsetX;
+                                NowLoadConfig.CameraConfig.CameraSNNum = CameraConfig.CameraSNNum;
+                                NowLoadConfig.CameraConfig.CameraName = CameraConfig.CameraName;
+                                NowLoadConfig.CameraConfig.DeviceName = CameraConfig.DeviceName;
+                                NowLoadConfig.ShuLiConfigClass.CameraSN = CameraConfig.CameraSNNum; 
                                 Configs[Nowindex] = NowLoadConfig;
                             }
                 }
                 else
                 {
                     MessageBox.Show("切换相机失败!");
-                    CameraConbox.SelectedItem = LoadMainThread.ThisCameraDevice + "_" + LoadMainThread.ThisCameraSN;
+                    CameraConbox.SelectedItem = LoadMainThread.cameraConfig.DeviceName + "_" + LoadMainThread.cameraConfig.CameraSNNum;
                     return;
                 }
             }
@@ -531,7 +530,7 @@ namespace CCDCount.Forms
                                       "切换确认", MessageBoxButtons.YesNo);
                     if (confirmResult == DialogResult.No)
                     {
-                        CameraConbox.SelectedItem = LoadMainThread.ThisCameraDevice + "_" + LoadMainThread.ThisCameraSN;
+                        CameraConbox.SelectedItem = LoadMainThread.cameraConfig.DeviceName + "_" + LoadMainThread.cameraConfig.CameraSNNum;
                         return;
                     }
                     LoadMainThread.StopMianThread();
@@ -541,21 +540,21 @@ namespace CCDCount.Forms
                     LoadMainThread.DisposeCamera();
                 }
                 ExposureTimeTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.ExposureTimeValue = 0;
+                NowLoadConfig.CameraConfig.ExposureTimeValue = 0;
                 AcquistionLineRateLabTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.AcquistionLineRateValue = 0;
+                NowLoadConfig.CameraConfig.AcquistionLineRateValue = 0;
                 ImageWidthTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.Width = 0;
+                NowLoadConfig.CameraConfig.Width = 0;
                 ImageHeightTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.Height = 0;
+                NowLoadConfig.CameraConfig.Height = 0;
                 CamUserNameTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.CameraName = string.Empty;
+                NowLoadConfig.CameraConfig.CameraName = string.Empty;
                 CamOffsetXTbx.Text = string.Empty;
-                NowLoadConfig.CameraConfigValue.OffsetX = 0;
-                NowLoadConfig.CameraConfigValue.CameraSNNum = string.Empty;
-                NowLoadConfig.CameraConfigValue.CameraName = string.Empty;
-                NowLoadConfig.CameraConfigValue.DeviceName = string.Empty;
-                NowLoadConfig.ShuLiConfigValue.CameraSN = string.Empty;
+                NowLoadConfig.CameraConfig.OffsetX = 0;
+                NowLoadConfig.CameraConfig.CameraSNNum = string.Empty;
+                NowLoadConfig.CameraConfig.CameraName = string.Empty;
+                NowLoadConfig.CameraConfig.DeviceName = string.Empty;
+                NowLoadConfig.ShuLiConfigClass.CameraSN = string.Empty;
                 Configs[Nowindex] = NowLoadConfig;
             }
         }

+ 43 - 0
TestWork/ShowBindingClass.cs

@@ -0,0 +1,43 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media.Imaging;
+
+namespace CCDCountWpf
+{
+    public class ShowBindingClass : INotifyPropertyChanged
+    {
+
+        private string teststring = "测试";
+        public string TestString
+        {
+            get { return teststring; }
+            set
+            {
+                teststring = value;
+                OnPropertyChanged("TestString");
+            }
+        }
+
+        private BitmapImage bitmapImage;
+        public BitmapImage BitmapImage
+        {
+            get { return bitmapImage; }
+            set
+            {
+                bitmapImage = value;
+                OnPropertyChanged("BitmapImage");
+            }
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected void OnPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}