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
{
/// 设置页 - 相机管理(属性 + 操作)
public partial class SettingViewModel
{
#region 相机管理
public ObservableCollection Cameras { get; }
public ObservableCollection 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;
/// 选中相机的运行时实例——内联属性编辑器直接编辑它(修改即实时下发硬件),不再走双击弹窗
public ICamera SelectedCameraDevice
{
get { return _selectedCameraDevice; }
private set { SetProperty(ref _selectedCameraDevice, value); }
}
/// 当前正在采集的相机实例——设置页同一时间只允许一路预览,防止多路画面串页
private ICamera _grabbingCamera;
private object _currentDebugPage;
/// 右侧调试页容器的内容:按 [Camera] 特性加载品牌专属页,未指定则用默认页
public object CurrentDebugPage
{
get { return _currentDebugPage; }
private set { SetProperty(ref _currentDebugPage, value); }
}
/// 按选中的相机刷新右侧调试页与属性编辑器的绑定目标
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);
}
/// 停掉指定相机的采集并退订帧事件(按 Id 同步列表行的采集状态标记)
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
}
}