diff --git a/BOB.sln b/BOB.sln
index 0ebc5f9..78585c8 100644
--- a/BOB.sln
+++ b/BOB.sln
@@ -17,6 +17,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Command", "Command\Command.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeviceCommand", "DeviceCommand\DeviceCommand.csproj", "{94177FB3-45E4-466E-BB9F-761295736D35}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessManager", "ProcessManager\ProcessManager.csproj", "{269FEC4B-B5AD-4BE8-853F-56C37A3557A6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{E2897246-96B3-48BE-AA08-4E774BE2BCFB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -51,6 +55,14 @@ Global
{94177FB3-45E4-466E-BB9F-761295736D35}.Debug|Any CPU.Build.0 = Debug|Any CPU
{94177FB3-45E4-466E-BB9F-761295736D35}.Release|Any CPU.ActiveCfg = Release|Any CPU
{94177FB3-45E4-466E-BB9F-761295736D35}.Release|Any CPU.Build.0 = Release|Any CPU
+ {269FEC4B-B5AD-4BE8-853F-56C37A3557A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {269FEC4B-B5AD-4BE8-853F-56C37A3557A6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {269FEC4B-B5AD-4BE8-853F-56C37A3557A6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {269FEC4B-B5AD-4BE8-853F-56C37A3557A6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E2897246-96B3-48BE-AA08-4E774BE2BCFB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/BOB/BOB.csproj b/BOB/BOB.csproj
index 898faab..ee993ec 100644
--- a/BOB/BOB.csproj
+++ b/BOB/BOB.csproj
@@ -47,6 +47,7 @@
+
diff --git a/BOB/SystemConfig.cs b/BOB/SystemConfig.cs
index 7e1f5c0..adafe9d 100644
--- a/BOB/SystemConfig.cs
+++ b/BOB/SystemConfig.cs
@@ -1,7 +1,7 @@
using BOB.Models;
using Logger;
using Newtonsoft.Json;
-using System;
+using Model;
using System.IO;
using System.Reflection;
diff --git a/BOB/Models/DeviceConfigModel.cs b/Model/DeviceConfigModel.cs
similarity index 98%
rename from BOB/Models/DeviceConfigModel.cs
rename to Model/DeviceConfigModel.cs
index 7319518..59cf904 100644
--- a/BOB/Models/DeviceConfigModel.cs
+++ b/Model/DeviceConfigModel.cs
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace BOB.Models
+namespace Model
{
public class DeviceConfigModel
{
diff --git a/Model/Model.csproj b/Model/Model.csproj
index fa71b7a..87bda1a 100644
--- a/Model/Model.csproj
+++ b/Model/Model.csproj
@@ -6,4 +6,8 @@
enable
+
+
+
+
diff --git a/ProcessManager/App.xaml b/ProcessManager/App.xaml
new file mode 100644
index 0000000..8db957e
--- /dev/null
+++ b/ProcessManager/App.xaml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ProcessManager/App.xaml.cs b/ProcessManager/App.xaml.cs
new file mode 100644
index 0000000..460b82e
--- /dev/null
+++ b/ProcessManager/App.xaml.cs
@@ -0,0 +1,37 @@
+using BOB;
+using BOB.ViewModels;
+using BOB.ViewModels.Dialogs;
+using BOB.Views;
+using BOB.Views.Dialogs;
+using Prism.Ioc;
+using ProcessManager.ViewModels;
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace ProcessManager
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : PrismApplication
+ {
+ protected override Window CreateShell()
+ {
+ return Container.Resolve();
+ }
+ protected override void OnInitialized()
+ {
+ base.OnInitialized();
+
+
+ }
+ protected override void RegisterTypes(IContainerRegistry containerRegistry)
+ {
+ containerRegistry.RegisterForNavigation();
+ containerRegistry.RegisterDialog("Setting");
+ }
+
+ }
+
+}
diff --git a/ProcessManager/AssemblyInfo.cs b/ProcessManager/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/ProcessManager/AssemblyInfo.cs
@@ -0,0 +1,10 @@
+using System.Windows;
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
diff --git a/ProcessManager/JsonHelper.cs b/ProcessManager/JsonHelper.cs
new file mode 100644
index 0000000..19adeab
--- /dev/null
+++ b/ProcessManager/JsonHelper.cs
@@ -0,0 +1,64 @@
+using BOB;
+using Newtonsoft.Json;
+using System;
+using System.IO;
+
+namespace ProcessManager
+{
+ public class JsonHelper
+ {
+ private static readonly object _lock = new();
+ public static string SystemPath { get; set; } =
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "BOB");
+
+ private static string ConfigFile => Path.Combine(SystemPath, "system.json");
+
+ private static readonly JsonSerializerSettings jsonSettings = new()
+ {
+ TypeNameHandling = TypeNameHandling.All, // 必须开启
+ Formatting = Formatting.Indented,
+ MetadataPropertyHandling = MetadataPropertyHandling.ReadAhead,
+ };
+
+ #region 配置保存
+ public static void SaveToFile(SystemConfig config)
+ {
+ lock (_lock)
+ {
+ if (!Directory.Exists(SystemPath))
+ Directory.CreateDirectory(SystemPath);
+
+ string json = JsonConvert.SerializeObject(config, jsonSettings);
+ File.WriteAllText(ConfigFile, json);
+ }
+ }
+ #endregion
+
+ #region 配置加载
+ public static SystemConfig LoadFromFile()
+ {
+ lock (_lock)
+ {
+ if (!File.Exists(ConfigFile))
+ {
+ // 如果不存在自动创建一个默认的 SystemConfig
+ var defaultConfig = new SystemConfig();
+ SaveToFile(defaultConfig);
+ return defaultConfig;
+ }
+
+ try
+ {
+ string json = File.ReadAllText(ConfigFile);
+ return JsonConvert.DeserializeObject(json, jsonSettings);
+ }
+ catch (Exception ex)
+ {
+ // 如果反序列化失败,避免程序崩溃
+ throw new Exception("系统配置加载失败: " + ex.Message);
+ }
+ }
+ }
+ #endregion
+ }
+}
diff --git a/ProcessManager/MainWindow.xaml b/ProcessManager/MainWindow.xaml
new file mode 100644
index 0000000..aa16972
--- /dev/null
+++ b/ProcessManager/MainWindow.xaml
@@ -0,0 +1,188 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ProcessManager/MainWindow.xaml.cs b/ProcessManager/MainWindow.xaml.cs
new file mode 100644
index 0000000..7b7a9a0
--- /dev/null
+++ b/ProcessManager/MainWindow.xaml.cs
@@ -0,0 +1,25 @@
+using MahApps.Metro.Controls;
+using MaterialDesignThemes.Wpf;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+
+
+namespace ProcessManager
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : MetroWindow
+ {
+
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+
+
+ }
+}
\ No newline at end of file
diff --git a/ProcessManager/ProcessManager.csproj b/ProcessManager/ProcessManager.csproj
new file mode 100644
index 0000000..98c0d5b
--- /dev/null
+++ b/ProcessManager/ProcessManager.csproj
@@ -0,0 +1,15 @@
+
+
+
+ WinExe
+ net8.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+
+
diff --git a/ProcessManager/Setting.xaml b/ProcessManager/Setting.xaml
new file mode 100644
index 0000000..8c7e2d8
--- /dev/null
+++ b/ProcessManager/Setting.xaml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ProcessManager/Setting.xaml.cs b/ProcessManager/Setting.xaml.cs
new file mode 100644
index 0000000..5004b52
--- /dev/null
+++ b/ProcessManager/Setting.xaml.cs
@@ -0,0 +1,19 @@
+using BOB;
+using MaterialDesignThemes.Wpf;
+using System.Windows;
+using System.Windows.Controls;
+
+
+namespace ProcessManager
+{
+ ///
+ /// Setting.xaml 的交互逻辑
+ ///
+ public partial class Setting : UserControl
+ {
+ public Setting()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/ProcessManager/ViewModels/PMainViewModel.cs b/ProcessManager/ViewModels/PMainViewModel.cs
new file mode 100644
index 0000000..7bbfbf8
--- /dev/null
+++ b/ProcessManager/ViewModels/PMainViewModel.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection.Metadata;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+
+namespace ProcessManager.ViewModels
+{
+ public class PMainViewModel:BindableBase
+ {
+ private readonly IDialogService _dialogService;
+ private Dictionary ProcessDic { get; set; } = new Dictionary();
+ public ICommand StartCommand { get; set; }
+ public ICommand EditCommand { get; set; }
+ public PMainViewModel(IDialogService dialogService)
+ {
+ _dialogService = dialogService;
+ EditCommand=new DelegateCommand(OnEdit);
+ StartCommand = new DelegateCommand(OnStart);
+ }
+
+ private void OnStart(string deviceName)
+ {
+ if (ProcessDic.ContainsKey(deviceName))
+ {
+ MessageBox.Show("进程已启动");
+ return;
+ }
+ try
+ {
+ string currentDir = Environment.CurrentDirectory;
+ string exePath = Path.Combine(currentDir, "BOB.exe");
+ if (!File.Exists(exePath))
+ {
+ MessageBox.Show($"未找到文件: {exePath}");
+ return;
+ }
+ ProcessStartInfo startInfo = new ProcessStartInfo
+ {
+ FileName = exePath,
+ UseShellExecute = true
+ };
+ var process = Process.Start(startInfo);
+ process.EnableRaisingEvents = true;
+ process.Exited += (s, args) =>
+ {
+ ProcessDic.Remove(deviceName);
+ };
+ ProcessDic.Add(deviceName, process);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"启动失败: {ex.Message}");
+ }
+ }
+
+ private void OnEdit(string deviceName)
+ {
+ if (ProcessDic.ContainsKey(deviceName))
+ {
+ MessageBox.Show("请先关闭进程再进行编辑");
+ return;
+ }
+ var ConfigSystem = JsonHelper.LoadFromFile();
+ var parameters = new DialogParameters
+ {
+ { "SystemConfig", ConfigSystem },
+ { "Title", deviceName }
+ };
+
+ _dialogService.ShowDialog("Setting", parameters, r =>
+ {
+ if (r.Result == ButtonResult.OK)
+ {
+ // 用户点击 OK
+ }
+ });
+ }
+ }
+}
diff --git a/ProcessManager/ViewModels/SettingViewModel.cs b/ProcessManager/ViewModels/SettingViewModel.cs
new file mode 100644
index 0000000..8e49564
--- /dev/null
+++ b/ProcessManager/ViewModels/SettingViewModel.cs
@@ -0,0 +1,75 @@
+using BOB;
+using BOB.Models;
+using Model;
+using Prism.Mvvm;
+using System.Collections.ObjectModel;
+using System.Windows.Input;
+
+namespace ProcessManager.ViewModels
+{
+ public class SettingViewModel : BindableBase, IDialogAware
+ {
+ private string _Title;
+
+ public string Title
+ {
+ get => _Title;
+ set => SetProperty(ref _Title, value);
+ }
+ private DeviceConfigModel _SelectedDevice;
+
+ public DeviceConfigModel SelectedDevice
+ {
+ get => _SelectedDevice;
+ set => SetProperty(ref _SelectedDevice, value);
+ }
+
+ private SystemConfig _config;
+ public SystemConfig Config
+ {
+ get => _config;
+ set => SetProperty(ref _config, value);
+ }
+
+ public ObservableCollection Devices { get; set; } = new ObservableCollection();
+
+ public DialogCloseListener RequestClose { get; set; }
+ public ICommand SaveCommand { get; set; }
+ public ICommand CancelCommand { get; set; }
+ public SettingViewModel()
+ {
+ CancelCommand = new DelegateCommand(Cancel);
+ SaveCommand = new DelegateCommand(Save);
+ }
+
+ private void Save()
+ {
+ RequestClose.Invoke();
+ }
+
+ private void Cancel()
+ {
+ RequestClose.Invoke();
+ }
+
+ public bool CanCloseDialog() => true;
+
+ public void OnDialogClosed() { }
+
+ public void OnDialogOpened(IDialogParameters parameters)
+ {
+ // 从参数获取 SystemConfig
+ if (parameters.ContainsKey("SystemConfig"))
+ {
+ Config = parameters.GetValue("SystemConfig");
+ Devices.Clear();
+ foreach (var d in Config.DeviceList)
+ Devices.Add(d);
+ }
+ if (parameters.ContainsKey("Title"))
+ {
+ Title= parameters.GetValue("Title");
+ }
+ }
+ }
+}