diff --git a/XplorePlane/App.config b/XplorePlane/App.config
index 7d6d23c..7465d52 100644
--- a/XplorePlane/App.config
+++ b/XplorePlane/App.config
@@ -88,6 +88,11 @@
+
+
+
+
+
@@ -164,4 +169,4 @@
-
\ No newline at end of file
+
diff --git a/XplorePlane/App.xaml.cs b/XplorePlane/App.xaml.cs
index bd10aa4..57f657f 100644
--- a/XplorePlane/App.xaml.cs
+++ b/XplorePlane/App.xaml.cs
@@ -13,10 +13,10 @@ using XP.Camera;
using XP.Common.Configs;
using XP.Common.Database.Implementations;
using XP.Common.Database.Interfaces;
-using XP.Common.GeneralForm.Views;
using XP.Common.Dump.Configs;
using XP.Common.Dump.Implementations;
using XP.Common.Dump.Interfaces;
+using XP.Common.GeneralForm.Views;
using XP.Common.Helpers;
using XP.Common.Localization.Configs;
using XP.Common.Localization.Extensions;
@@ -35,9 +35,10 @@ using XplorePlane.Services;
using XplorePlane.Services.AppState;
using XplorePlane.Services.Camera;
using XplorePlane.Services.Cnc;
+using XplorePlane.Services.InspectionResults;
+using XplorePlane.Services.MainViewport;
using XplorePlane.Services.Matrix;
using XplorePlane.Services.Measurement;
-using XplorePlane.Services.InspectionResults;
using XplorePlane.Services.Recipe;
using XplorePlane.ViewModels;
using XplorePlane.ViewModels.Cnc;
@@ -51,10 +52,10 @@ namespace XplorePlane
///
public partial class App : Application
{
- protected override void OnStartup(StartupEventArgs e)
- {
- // 设置 Telerik Windows11 主题,缩小 Ribbon 整体尺寸
- StyleManager.ApplicationTheme = new Windows11Theme();
+ protected override void OnStartup(StartupEventArgs e)
+ {
+ // 设置 Telerik Windows11 主题,缩小 Ribbon 整体尺寸
+ StyleManager.ApplicationTheme = new Windows11Theme();
// 强制使用中文 UI,确保 ImageProcessing 库显示中文
var zhCN = new CultureInfo("zh-CN");
@@ -66,8 +67,8 @@ namespace XplorePlane
// 配置 Serilog 日志系统
ConfigureLogging();
- // 捕获未处理的异常
- AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
+ // 捕获未处理的异常
+ AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
DispatcherUnhandledException += OnDispatcherUnhandledException;
try
@@ -102,12 +103,12 @@ namespace XplorePlane
private void ConfigureLogging()
{
- // 加载Serilog配置 | Load Serilog configuration
- SerilogConfig serilogConfig = ConfigLoader.LoadSerilogConfig();
- // 初始化Serilog(全局唯一)| Initialize Serilog (global singleton)
- SerilogInitializer.Initialize(serilogConfig);
+ // 加载 Serilog 配置 | Load Serilog configuration
+ SerilogConfig serilogConfig = ConfigLoader.LoadSerilogConfig();
+ // 初始化 Serilog(全局唯一)| Initialize Serilog (global singleton)
+ SerilogInitializer.Initialize(serilogConfig);
- // 记录应用启动日志 | Log application startup
+ // 记录应用启动日志 | Log application startup
Log.Information("========================================");
Log.Information("XplorePlane 应用程序启动");
Log.Information("========================================");
@@ -183,23 +184,39 @@ namespace XplorePlane
Log.Error(ex, "导航相机服务资源释放失败");
}
- // 释放SQLite数据库资源 | Release SQLite database resources
- try
- {
- var bootstrapper = AppBootstrapper.Instance;
+ // 释放主界面探测器帧流水线资源
+ try
+ {
+ var bootstrapper = AppBootstrapper.Instance;
if (bootstrapper != null)
{
- var dbContext = bootstrapper.Container.Resolve(); // 从Prism容器获取IDbContext实例(单例)| Get IDbContext instance from Prism container (singleton)
+ var detectorFramePipelineService = bootstrapper.Container.Resolve();
+ detectorFramePipelineService?.Dispose();
+ Log.Information("主界面探测器帧流水线资源已释放");
+ }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "主界面探测器帧流水线资源释放失败");
+ }
+
+ // 释放SQLite数据库资源 | Release SQLite database resources
+ try
+ {
+ var bootstrapper = AppBootstrapper.Instance;
+ if (bootstrapper != null)
+ {
+ var dbContext = bootstrapper.Container.Resolve(); // 从 Prism 容器获取 IDbContext 实例(单例)| Get IDbContext instance from Prism container (singleton)
dbContext?.Dispose();
Log.Information("数据库资源已成功释放 | Database resources released successfully");
}
- }
- catch (Exception ex)
- {
- Log.Error(ex, "数据库资源释放失败,忽略该错误继续退出 | Database resource release failed, ignoring error and continuing exit");
- }
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "数据库资源释放失败,忽略该错误继续退出 | Database resource release failed, ignoring error and continuing exit");
+ }
- Log.CloseAndFlush();
+ Log.CloseAndFlush();
base.OnExit(e);
}
@@ -208,7 +225,7 @@ namespace XplorePlane
///
private void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
{
- var exception = e.ExceptionObject as Exception;
+ var exception = e.ExceptionObject as Exception;
Log.Fatal(exception, "应用程序发生未处理的异常");
MessageBox.Show(
@@ -242,15 +259,15 @@ namespace XplorePlane
public new IContainerProvider Container => base.Container;
+ private bool _modulesInitialized = false;
+
+ private string _cameraError;
+
public AppBootstrapper()
{
Instance = this;
}
- private bool _modulesInitialized = false;
-
- private string? _cameraError;
-
protected override Window CreateShell()
{
// 提前初始化模块,确保硬件服务在 MainWindow XAML 解析前已注册
@@ -267,6 +284,16 @@ namespace XplorePlane
{
TryConnectCamera();
+ // 初始化主界面探测器帧流水线,开始接收探测器图像事件
+ try
+ {
+ _ = Container.Resolve();
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "初始化主界面探测器帧流水线失败");
+ }
+
// 通知 ViewModel 相机状态已确定,启动实时预览或显示错误
try
{
@@ -329,11 +356,11 @@ namespace XplorePlane
// 注册 Serilog 的 ILogger 实例
containerRegistry.RegisterInstance(Log.Logger);
- // 注册 XP.Common.ILoggerService 适配器
- containerRegistry.RegisterSingleton();
+ // 注册 XP.Common.ILoggerService 适配器
+ containerRegistry.RegisterSingleton();
- // 注册视图和视图模型
- containerRegistry.RegisterForNavigation();
+ // 注册视图和视图模型
+ containerRegistry.RegisterForNavigation();
containerRegistry.Register();
containerRegistry.RegisterSingleton();
@@ -364,16 +391,7 @@ namespace XplorePlane
containerRegistry.RegisterInstance(sqliteConfig);
containerRegistry.RegisterSingleton();
- // 注册硬件库的 ViewModel(供 ViewModelLocator 自动装配)
- //containerRegistry.Register();
- // 手动注册射线源模块的所有服务(确保 DryIoc 容器中可用,避免模块加载顺序问题)
- //var raySourceConfig = XP.Hardware.RaySource.Config.ConfigLoader.LoadConfig();
- //containerRegistry.RegisterInstance(raySourceConfig);
- //containerRegistry.RegisterSingleton();
- //containerRegistry.RegisterSingleton();
- //containerRegistry.RegisterSingleton();
-
- // 手动注册通用模块的服务(本地化、Dump)
+ // 注册通用模块的服务(本地化、Dump)
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton(() => XP.Common.Helpers.ConfigLoader.LoadDumpConfig());
@@ -385,6 +403,10 @@ namespace XplorePlane
containerRegistry.RegisterSingleton();
containerRegistry.RegisterSingleton();
+ // ── 主界面实时图像 / 探测器双队列服务(单例)──
+ containerRegistry.RegisterSingleton();
+ containerRegistry.RegisterSingleton();
+
// ── CNC / 矩阵 ViewModel(瞬态)──
containerRegistry.Register();
containerRegistry.Register();
@@ -405,13 +427,13 @@ namespace XplorePlane
protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
- // 所有模块服务已在 RegisterTypes 中手动注册
- // CommonModule: ILocalizationService, IDumpService
- // RaySourceModule: IRaySourceService, IRaySourceFactory, IFilamentLifetimeService
+ // 所有模块服务已在 RegisterTypes 中手动注册
+ // CommonModule: ILocalizationService, IDumpService
+ // RaySourceModule: IRaySourceService, IRaySourceFactory, IFilamentLifetimeService
+
+ // 注册通用模块(必须最先加载)| Register common module (must be loaded first)
+ moduleCatalog.AddModule();
- // 注册通用模块(必须最先加载)| Register common module (must be loaded first)
- moduleCatalog.AddModule();
-
// 注册其他模块 | Register other modules
moduleCatalog.AddModule();
moduleCatalog.AddModule();
diff --git a/XplorePlane/Services/MainViewport/DetectorFrame.cs b/XplorePlane/Services/MainViewport/DetectorFrame.cs
new file mode 100644
index 0000000..9fd7cb0
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/DetectorFrame.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Windows.Media.Imaging;
+
+namespace XplorePlane.Services.MainViewport
+{
+ public sealed class DetectorFrame
+ {
+ public DetectorFrame(
+ long frameId,
+ DateTime captureTime,
+ int width,
+ int height,
+ ushort[] rawPixels,
+ BitmapSource previewImage)
+ {
+ FrameId = frameId;
+ CaptureTime = captureTime;
+ Width = width;
+ Height = height;
+ RawPixels = rawPixels;
+ PreviewImage = previewImage;
+ }
+
+ public long FrameId { get; }
+ public DateTime CaptureTime { get; }
+ public int Width { get; }
+ public int Height { get; }
+ public ushort[] RawPixels { get; }
+ public BitmapSource PreviewImage { get; }
+ }
+}
diff --git a/XplorePlane/Services/MainViewport/DetectorFramePipelineService.cs b/XplorePlane/Services/MainViewport/DetectorFramePipelineService.cs
new file mode 100644
index 0000000..46c5bb5
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/DetectorFramePipelineService.cs
@@ -0,0 +1,160 @@
+using Prism.Events;
+using System;
+using System.Collections.Concurrent;
+using System.Configuration;
+using System.Threading;
+using System.Threading.Tasks;
+using XP.Common.Converters;
+using XP.Common.Logging.Interfaces;
+using XP.Hardware.Detector.Abstractions;
+using XP.Hardware.Detector.Abstractions.Events;
+
+namespace XplorePlane.Services.MainViewport
+{
+ public sealed class DetectorFramePipelineService : IDetectorFramePipelineService
+ {
+ private readonly ConcurrentQueue _acquireQueue = new();
+ private readonly ConcurrentQueue _processQueue = new();
+ private readonly SemaphoreSlim _processSignal = new(0);
+ private readonly CancellationTokenSource _shutdown = new();
+ private readonly IMainViewportService _mainViewportService;
+ private readonly ILoggerService _logger;
+ private readonly Task _processConsumerTask;
+ private int _acquireQueueCount;
+ private int _processQueueCount;
+ private long _receivedFrameCount;
+ private bool _disposed;
+
+ public DetectorFramePipelineService(
+ IEventAggregator eventAggregator,
+ IMainViewportService mainViewportService,
+ ILoggerService logger)
+ {
+ ArgumentNullException.ThrowIfNull(eventAggregator);
+ _mainViewportService = mainViewportService ?? throw new ArgumentNullException(nameof(mainViewportService));
+ _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger));
+
+ AcquireQueueCapacity = ReadInt("DetectorPipeline:AcquireQueueCapacity", 16, 1);
+ ProcessQueueCapacity = ReadInt("DetectorPipeline:ProcessQueueCapacity", 8, 1);
+ ProcessEveryNFrames = ReadInt("DetectorPipeline:ProcessEveryNFrames", 1, 1);
+
+ eventAggregator.GetEvent()
+ .Subscribe(OnImageCaptured, ThreadOption.BackgroundThread);
+
+ _processConsumerTask = Task.Run(ProcessLoopAsync);
+ }
+
+ public int AcquireQueueCount => Volatile.Read(ref _acquireQueueCount);
+ public int ProcessQueueCount => Volatile.Read(ref _processQueueCount);
+ public int AcquireQueueCapacity { get; }
+ public int ProcessQueueCapacity { get; }
+ public int ProcessEveryNFrames { get; }
+
+ public event EventHandler ProcessFrameDequeued;
+
+ private void OnImageCaptured(ImageCapturedEventArgs args)
+ {
+ if (_disposed || args?.ImageData == null || args.Width <= 0 || args.Height <= 0)
+ return;
+
+ try
+ {
+ var rawPixels = new ushort[args.ImageData.Length];
+ Array.Copy(args.ImageData, rawPixels, rawPixels.Length);
+
+ var bitmap = XP.Common.Converters.ImageConverter.ConvertGray16ToBitmapSource(rawPixels, (int)args.Width, (int)args.Height);
+ bitmap.Freeze();
+
+ var frame = new DetectorFrame(
+ frameId: args.FrameNumber,
+ captureTime: args.CaptureTime,
+ width: (int)args.Width,
+ height: (int)args.Height,
+ rawPixels: rawPixels,
+ previewImage: bitmap);
+
+ EnqueueBounded(_acquireQueue, frame, AcquireQueueCapacity, ref _acquireQueueCount);
+ _mainViewportService.UpdateDetectorFrame(frame);
+
+ var sequence = Interlocked.Increment(ref _receivedFrameCount);
+ if ((sequence - 1) % ProcessEveryNFrames == 0)
+ {
+ EnqueueBounded(_processQueue, frame, ProcessQueueCapacity, ref _processQueueCount);
+ _processSignal.Release();
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, "探测器帧进入主界面流水线失败");
+ }
+ }
+
+ private async Task ProcessLoopAsync()
+ {
+ try
+ {
+ while (!_shutdown.IsCancellationRequested)
+ {
+ await _processSignal.WaitAsync(_shutdown.Token).ConfigureAwait(false);
+
+ while (_processQueue.TryDequeue(out var frame))
+ {
+ Interlocked.Decrement(ref _processQueueCount);
+ ProcessFrameDequeued?.Invoke(this, frame);
+ }
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, "探测器处理队列后台消费者异常退出");
+ }
+ }
+
+ private static void EnqueueBounded(
+ ConcurrentQueue queue,
+ DetectorFrame frame,
+ int capacity,
+ ref int queueCount)
+ {
+ queue.Enqueue(frame);
+ var count = Interlocked.Increment(ref queueCount);
+
+ while (count > capacity && queue.TryDequeue(out _))
+ {
+ count = Interlocked.Decrement(ref queueCount);
+ }
+ }
+
+ private static int ReadInt(string key, int defaultValue, int minValue)
+ {
+ var raw = ConfigurationManager.AppSettings[key];
+ if (!int.TryParse(raw, out var parsed))
+ return defaultValue;
+
+ return parsed < minValue ? minValue : parsed;
+ }
+
+ public void Dispose()
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+ _shutdown.Cancel();
+
+ try
+ {
+ _processConsumerTask.Wait(TimeSpan.FromSeconds(2));
+ }
+ catch
+ {
+ }
+
+ _processSignal.Dispose();
+ _shutdown.Dispose();
+ }
+ }
+}
diff --git a/XplorePlane/Services/MainViewport/IDetectorFramePipelineService.cs b/XplorePlane/Services/MainViewport/IDetectorFramePipelineService.cs
new file mode 100644
index 0000000..24d9cea
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/IDetectorFramePipelineService.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace XplorePlane.Services.MainViewport
+{
+ public interface IDetectorFramePipelineService : IDisposable
+ {
+ int AcquireQueueCount { get; }
+ int ProcessQueueCount { get; }
+ int AcquireQueueCapacity { get; }
+ int ProcessQueueCapacity { get; }
+ int ProcessEveryNFrames { get; }
+
+ event EventHandler ProcessFrameDequeued;
+ }
+}
diff --git a/XplorePlane/Services/MainViewport/IMainViewportService.cs b/XplorePlane/Services/MainViewport/IMainViewportService.cs
new file mode 100644
index 0000000..a9247bc
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/IMainViewportService.cs
@@ -0,0 +1,25 @@
+using System;
+using System.Windows.Media;
+
+namespace XplorePlane.Services.MainViewport
+{
+ public interface IMainViewportService
+ {
+ MainViewportSourceMode CurrentSourceMode { get; }
+ bool IsRealtimeDisplayEnabled { get; }
+ ImageSource CurrentDisplayImage { get; }
+ string CurrentDisplayInfo { get; }
+ ImageSource LatestDetectorImage { get; }
+ ImageSource LatestManualImage { get; }
+
+ event EventHandler StateChanged;
+
+ void SetRealtimeDisplayEnabled(bool isEnabled);
+
+ void SetSourceMode(MainViewportSourceMode sourceMode);
+
+ void UpdateDetectorFrame(DetectorFrame frame);
+
+ void SetManualImage(ImageSource image, string filePath);
+ }
+}
diff --git a/XplorePlane/Services/MainViewport/MainViewportService.cs b/XplorePlane/Services/MainViewport/MainViewportService.cs
new file mode 100644
index 0000000..ac13c50
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/MainViewportService.cs
@@ -0,0 +1,214 @@
+using System;
+using System.Configuration;
+using System.IO;
+using System.Windows.Media;
+using XP.Common.Logging.Interfaces;
+
+namespace XplorePlane.Services.MainViewport
+{
+ public sealed class MainViewportService : IMainViewportService
+ {
+ private readonly object _syncRoot = new();
+ private readonly ILoggerService _logger;
+
+ private MainViewportSourceMode _currentSourceMode = MainViewportSourceMode.LiveDetector;
+ private bool _isRealtimeDisplayEnabled;
+ private ImageSource _currentDisplayImage;
+ private string _currentDisplayInfo = "等待探测器图像...";
+ private ImageSource _latestDetectorImage;
+ private string _latestDetectorInfo = "等待探测器图像...";
+ private ImageSource _latestManualImage;
+ private string _latestManualInfo = "未加载手动图像";
+
+ public MainViewportService(ILoggerService logger)
+ {
+ _logger = logger?.ForModule() ?? throw new ArgumentNullException(nameof(logger));
+ _isRealtimeDisplayEnabled = ReadBoolean("MainViewport:RealtimeEnabledDefault", true);
+ }
+
+ public MainViewportSourceMode CurrentSourceMode
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _currentSourceMode;
+ }
+ }
+ }
+
+ public bool IsRealtimeDisplayEnabled
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _isRealtimeDisplayEnabled;
+ }
+ }
+ }
+
+ public ImageSource CurrentDisplayImage
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _currentDisplayImage;
+ }
+ }
+ }
+
+ public string CurrentDisplayInfo
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _currentDisplayInfo;
+ }
+ }
+ }
+
+ public ImageSource LatestDetectorImage
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _latestDetectorImage;
+ }
+ }
+ }
+
+ public ImageSource LatestManualImage
+ {
+ get
+ {
+ lock (_syncRoot)
+ {
+ return _latestManualImage;
+ }
+ }
+ }
+
+ public event EventHandler StateChanged;
+
+ public void SetRealtimeDisplayEnabled(bool isEnabled)
+ {
+ bool changed;
+ lock (_syncRoot)
+ {
+ changed = _isRealtimeDisplayEnabled != isEnabled;
+ _isRealtimeDisplayEnabled = isEnabled;
+
+ if (_currentSourceMode == MainViewportSourceMode.LiveDetector && isEnabled)
+ {
+ ApplyLiveDetectorDisplay_NoLock();
+ }
+ }
+
+ if (!changed)
+ return;
+
+ _logger.Info("主界面实时刷新已{State}", isEnabled ? "开启" : "关闭");
+ RaiseStateChanged();
+ }
+
+ public void SetSourceMode(MainViewportSourceMode sourceMode)
+ {
+ bool changed;
+ lock (_syncRoot)
+ {
+ changed = _currentSourceMode != sourceMode;
+ _currentSourceMode = sourceMode;
+
+ switch (sourceMode)
+ {
+ case MainViewportSourceMode.LiveDetector:
+ ApplyLiveDetectorDisplay_NoLock();
+ break;
+ case MainViewportSourceMode.ManualImage:
+ ApplyManualDisplay_NoLock();
+ break;
+ }
+ }
+
+ if (!changed)
+ return;
+
+ _logger.Info("主界面图像来源已切换为 {Mode}", sourceMode);
+ RaiseStateChanged();
+ }
+
+ public void UpdateDetectorFrame(DetectorFrame frame)
+ {
+ if (frame == null)
+ return;
+
+ bool shouldRaise = false;
+ lock (_syncRoot)
+ {
+ _latestDetectorImage = frame.PreviewImage;
+ _latestDetectorInfo = $"实时探测器图像 {frame.Width}x{frame.Height} 帧#{frame.FrameId} {frame.CaptureTime:HH:mm:ss.fff}";
+
+ if (_currentSourceMode == MainViewportSourceMode.LiveDetector && _isRealtimeDisplayEnabled)
+ {
+ _currentDisplayImage = _latestDetectorImage;
+ _currentDisplayInfo = _latestDetectorInfo;
+ shouldRaise = true;
+ }
+ }
+
+ if (shouldRaise)
+ RaiseStateChanged();
+ }
+
+ public void SetManualImage(ImageSource image, string filePath)
+ {
+ if (image == null)
+ return;
+
+ var fileName = string.IsNullOrWhiteSpace(filePath) ? "未命名图像" : Path.GetFileName(filePath);
+
+ lock (_syncRoot)
+ {
+ _latestManualImage = image;
+ _latestManualInfo = $"手动加载图像 {fileName}";
+ _currentSourceMode = MainViewportSourceMode.ManualImage;
+ _currentDisplayImage = _latestManualImage;
+ _currentDisplayInfo = _latestManualInfo;
+ }
+
+ _logger.Info("主界面已加载手动图像 {FileName}", fileName);
+ RaiseStateChanged();
+ }
+
+ private void ApplyLiveDetectorDisplay_NoLock()
+ {
+ _currentDisplayImage = _latestDetectorImage;
+ _currentDisplayInfo = _latestDetectorImage == null
+ ? "等待探测器图像..."
+ : _latestDetectorInfo;
+ }
+
+ private void ApplyManualDisplay_NoLock()
+ {
+ _currentDisplayImage = _latestManualImage;
+ _currentDisplayInfo = _latestManualImage == null
+ ? "未加载手动图像"
+ : _latestManualInfo;
+ }
+
+ private void RaiseStateChanged()
+ {
+ StateChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ private static bool ReadBoolean(string key, bool defaultValue)
+ {
+ var raw = ConfigurationManager.AppSettings[key];
+ return bool.TryParse(raw, out var parsed) ? parsed : defaultValue;
+ }
+ }
+}
diff --git a/XplorePlane/Services/MainViewport/MainViewportSourceMode.cs b/XplorePlane/Services/MainViewport/MainViewportSourceMode.cs
new file mode 100644
index 0000000..3c778d0
--- /dev/null
+++ b/XplorePlane/Services/MainViewport/MainViewportSourceMode.cs
@@ -0,0 +1,8 @@
+namespace XplorePlane.Services.MainViewport
+{
+ public enum MainViewportSourceMode
+ {
+ LiveDetector = 0,
+ ManualImage = 1
+ }
+}
diff --git a/XplorePlane/ViewModels/Main/MainViewModel.cs b/XplorePlane/ViewModels/Main/MainViewModel.cs
index fdd75c9..fbfa353 100644
--- a/XplorePlane/ViewModels/Main/MainViewModel.cs
+++ b/XplorePlane/ViewModels/Main/MainViewModel.cs
@@ -1,15 +1,15 @@
-using Prism.Commands;
+using Microsoft.Win32;
+using Prism.Commands;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
-using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Windows;
using System.Windows.Media.Imaging;
-using XplorePlane.Events;
+using XplorePlane.Services.MainViewport;
using XplorePlane.ViewModels.Cnc;
using XplorePlane.Views;
using XplorePlane.Views.Cnc;
@@ -22,85 +22,13 @@ namespace XplorePlane.ViewModels
public class MainViewModel : BindableBase
{
private const double CncEditorHostWidth = 502d;
+
private readonly ILoggerService _logger;
private readonly IContainerProvider _containerProvider;
- private readonly IEventAggregator _eventAggregator;
+ private readonly IMainViewportService _mainViewportService;
private readonly CncEditorViewModel _cncEditorViewModel;
private readonly CncPageView _cncPageView;
- private string _licenseInfo = "当前时间";
- public string LicenseInfo
- {
- get => _licenseInfo;
- set => SetProperty(ref _licenseInfo, value);
- }
-
- public ObservableCollection