| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Drawing;
- using System.Windows;
- using System.Windows.Interop;
- using System.Windows.Media.Imaging;
- using TeamAAS.Camera;
- using TeamAAS.Camera.Images;
- using TeamAAS.Camera.Interfaces;
- using TeamAAS.Camera.Models;
- using TeamAAS.Camera.UI;
- using TeamAAS.Views;
- using System.Linq;
- namespace TeamAAS.ViewModels
- {
- /// <summary>设置页 - 相机管理(属性 + 操作)</summary>
- public partial class SettingViewModel
- {
- #region 相机管理
- public ObservableCollection<CameraInfo> Cameras { get; }
- public ObservableCollection<SdkStatusItem> SdkStatus { get; }
- private CameraInfo _selectedCamera;
- public CameraInfo SelectedCamera
- {
- get { return _selectedCamera; }
- set
- {
- if (SetProperty(ref _selectedCamera, value))
- RefreshDebugHost();
- RaisePropertyChanged(nameof(HasSelectedCamera));
- }
- }
- public bool HasSelectedCamera => _selectedCamera != null;
- private ICamera _selectedCameraDevice;
- /// <summary>选中相机的运行时实例——内联属性编辑器直接编辑它(修改即实时下发硬件),不再走双击弹窗</summary>
- public ICamera SelectedCameraDevice
- {
- get { return _selectedCameraDevice; }
- private set { SetProperty(ref _selectedCameraDevice, value); }
- }
- /// <summary>当前正在采集的相机实例——设置页同一时间只允许一路预览,防止多路画面串页</summary>
- private ICamera _grabbingCamera;
- private object _currentDebugPage;
- /// <summary>右侧调试页容器的内容:按 [Camera] 特性加载品牌专属页,未指定则用默认页</summary>
- public object CurrentDebugPage
- {
- get { return _currentDebugPage; }
- private set { SetProperty(ref _currentDebugPage, value); }
- }
- /// <summary>按选中的相机刷新右侧调试页与属性编辑器的绑定目标</summary>
- private void RefreshDebugHost()
- {
- // 旧页面解绑
- (_currentDebugPage as ICameraDebugPage)?.UnbindCamera();
- CurrentDebugPage = null;
- SelectedCameraDevice = null;
- if (_selectedCamera == null)
- {
- StopGrabbingInternal(_grabbingCamera);
- return;
- }
- var device = _cameraManager.GetCamera(_selectedCamera.Id);
- if (device == null)
- {
- StopGrabbingInternal(_grabbingCamera);
- return;
- }
- SelectedCameraDevice = device;
- // 切到另一台相机时停掉上一路采集,避免旧相机画面串进新调试页
- if (_grabbingCamera != null && !ReferenceEquals(_grabbingCamera, device))
- StopGrabbingInternal(_grabbingCamera);
- try
- {
- CurrentDebugPage = CameraDebugPageFactory.Create(device);
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"加载调试页失败: {ex.Message}");
- }
- }
- private BitmapSource _currentImage;
- public BitmapSource CurrentImage
- {
- get { return _currentImage; }
- set { SetProperty(ref _currentImage, value); }
- }
- private string _fpsText = "";
- public string FpsText
- {
- get { return _fpsText; }
- set { SetProperty(ref _fpsText, value); }
- }
- #endregion
- #region 相机操作
- private void LoadSdkStatus()
- {
- SdkStatus.Clear();
- try
- {
- var statusList = CameraManager.Instance.GetSdkStatus();
- foreach (var (Name, Installed, Version) in statusList)
- {
- SdkStatus.Add(new SdkStatusItem { Name = Name, Installed = Installed, Version = Version });
- }
- }
- catch { }
- }
- private void OpenSearchDialog()
- {
- var dialog = new SearchDeviceWindow
- {
- Owner = Application.Current.MainWindow
- };
- if (dialog.ShowDialog() == true)
- {
- foreach (var info in dialog.SelectedDevices)
- {
- try
- {
- if (_cameraManager.ContainsSN(info.SerialNumber))
- {
- DialogHelper.ShowWarning($"相机 {info.CameraName} 已存在");
- continue;
- }
- _cameraManager.CreateCamera(info.Id, info);
- info.CameraNo = Cameras.Count + 1;
- Cameras.Add(info);
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("添加相机失败", ex);
- }
- }
- }
- }
- private void DeleteCamera()
- {
- if (SelectedCamera == null) return;
- if (!DialogHelper.ConfirmYesNo(
- $"确认删除相机 \"{SelectedCamera.CameraName}\" 吗?",
- "确认删除"))
- {
- return;
- }
- var cameraToRemove = SelectedCamera;
- var id = cameraToRemove.Id;
- // 删除前先停掉该相机的采集与预览(退订帧事件),避免残留订阅推鬼帧
- if (_grabbingCamera != null && _grabbingCamera.ID == id)
- StopGrabbingInternal(_grabbingCamera);
- try
- {
- _cameraManager.RemoveCamera(id);
- }
- catch (Exception ex)
- {
- System.Diagnostics.Debug.WriteLine($"释放相机资源异常: {ex.Message}");
- }
- Cameras.Remove(cameraToRemove);
- for (int i = 0; i < Cameras.Count; i++)
- {
- Cameras[i].CameraNo = i + 1;
- }
- SelectedCamera = null;
- }
- private async System.Threading.Tasks.Task ConnectAsync()
- {
- if (SelectedCamera == null) return;
- try
- {
- var camera = _cameraManager.GetCamera(SelectedCamera.Id);
- if (camera == null)
- {
- DialogHelper.ShowWarning("未找到相机实例,请先添加");
- return;
- }
- bool success = await camera.OpenDeviceAsync();
- SelectedCamera.IsConnected = success;
- if (!success)
- {
- DialogHelper.ShowError($"相机连接失败: {camera.ErrorMessage}");
- }
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("连接失败", ex);
- }
- }
- private void Disconnect()
- {
- if (SelectedCamera == null) return;
- try
- {
- var camera = _cameraManager.GetCamera(SelectedCamera.Id);
- if (camera == null) return;
- if (camera.IsGrabbing)
- {
- camera.StopGrabbing();
- camera.ImageCallbackEvent -= OnImageCallback;
- SelectedCamera.IsGrabbing = false;
- }
- camera.CloseDevice();
- SelectedCamera.IsConnected = false;
- CurrentImage = null;
- FpsText = "";
- if (CurrentDebugPage is ICameraImageSink sinkClear)
- sinkClear.ShowImage(null);
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("断开失败", ex);
- }
- }
- private void StartGrabbing()
- {
- if (SelectedCamera == null) return;
- try
- {
- var camera = _cameraManager.GetCamera(SelectedCamera.Id);
- if (camera == null) return;
- // 同一时间只允许一路预览:采集另一台相机前先停掉当前这一路,
- // 否则旧相机的帧订阅仍在,两路画面会交替串进同一个调试页
- if (_grabbingCamera != null && !ReferenceEquals(_grabbingCamera, camera))
- StopGrabbingInternal(_grabbingCamera);
- if (!camera.IsConnected)
- {
- camera.OpenDevice();
- SelectedCamera.IsConnected = camera.IsConnected;
- }
- camera.ImageCallbackEvent += OnImageCallback;
- camera.StartGrabbing();
- SelectedCamera.IsGrabbing = true;
- _grabbingCamera = camera;
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("开始采集失败", ex);
- }
- }
- private void StopGrabbing()
- {
- var camera = _cameraManager.GetCamera(SelectedCamera?.Id ?? Guid.Empty);
- StopGrabbingInternal(camera ?? _grabbingCamera);
- }
- /// <summary>停掉指定相机的采集并退订帧事件(按 Id 同步列表行的采集状态标记)</summary>
- private void StopGrabbingInternal(ICamera camera)
- {
- if (camera == null) return;
- try
- {
- camera.StopGrabbing();
- camera.ImageCallbackEvent -= OnImageCallback;
- var info = Cameras?.FirstOrDefault(c => c.Id == camera.ID);
- if (info != null)
- {
- info.IsGrabbing = false;
- info.IsConnected = camera.IsConnected;
- }
- if (info != null && ReferenceEquals(SelectedCamera, info))
- {
- SelectedCamera.IsGrabbing = false;
- CurrentImage = null;
- FpsText = "";
- }
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("停止采集失败", ex);
- }
- finally
- {
- if (ReferenceEquals(_grabbingCamera, camera))
- _grabbingCamera = null;
- }
- }
- private void OnImageCallback(GenImage image, TimeSpan elapsed, string info)
- {
- if (image == null) return;
- try
- {
- var bitmap = image.ToBitmap();
- var hBitmap = bitmap.GetHbitmap();
- var bmpSource = Imaging.CreateBitmapSourceFromHBitmap(
- hBitmap, IntPtr.Zero, Int32Rect.Empty,
- BitmapSizeOptions.FromEmptyOptions());
- DeleteObject(hBitmap);
- bitmap.Dispose();
- bmpSource.Freeze();
- Application.Current?.Dispatcher?.BeginInvoke(new Action(() =>
- {
- CurrentImage = bmpSource;
- FpsText = elapsed.TotalMilliseconds > 0
- ? $"{1000.0 / elapsed.TotalMilliseconds:F1} fps"
- : "";
- // 把画面推送给当前调试页(若其具备图像接收能力)
- if (CurrentDebugPage is ICameraImageSink sink)
- sink.ShowImage(bmpSource);
- }));
- }
- catch { }
- }
- #endregion
- #region 相机列表刷新 & 配置保存
- private void RefreshCameraList()
- {
- var selectedId = SelectedCamera?.Id ?? Guid.Empty;
- Cameras.Clear();
- var infos = _cameraManager.GetAllCameraInfos();
- foreach (var info in infos)
- {
- Cameras.Add(info);
- }
- // 保持原选中项(重建调试页容器与属性编辑器绑定)
- if (selectedId != Guid.Empty)
- {
- var match = Cameras.FirstOrDefault(c => c.Id == selectedId);
- if (match != null && !ReferenceEquals(match, SelectedCamera))
- SelectedCamera = match;
- }
- }
- private void SaveCameraConfig()
- {
- try
- {
- if (_cameraManager.SaveConfig())
- {
- RefreshCameraList();
- DialogHelper.Success("相机配置已保存");
- }
- else
- DialogHelper.ShowError("相机配置保存失败,请查看日志");
- }
- catch (Exception ex)
- {
- DialogHelper.ShowError("保存相机配置失败", ex);
- }
- }
- #endregion
- }
- }
|