|
|
@@ -1,4 +1,5 @@
|
|
|
-using MaterialDesignThemes.Wpf;
|
|
|
+using Cognex.VisionPro;
|
|
|
+using MaterialDesignThemes.Wpf;
|
|
|
using MathNet.Numerics.LinearAlgebra;
|
|
|
using Prism.Commands;
|
|
|
using Prism.Events;
|
|
|
@@ -9,6 +10,7 @@ using Prism.Services.Dialogs;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Collections.ObjectModel;
|
|
|
+using System.Drawing;
|
|
|
using System.Linq;
|
|
|
using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
@@ -40,6 +42,9 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
IRobotService _robotService;
|
|
|
ISystemDatabaseService _systemDatabaseService;
|
|
|
IRemoteCommandService _remoteCommandService;
|
|
|
+ ICalibrationService _calibrationService;
|
|
|
+ ICameraService _cameraService;
|
|
|
+ CoordinateTransformer local = null;
|
|
|
|
|
|
#region 属性
|
|
|
|
|
|
@@ -278,7 +283,81 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
get { return _LockScrewProgramNumber; }
|
|
|
set { SetProperty(ref _LockScrewProgramNumber, value); }
|
|
|
}
|
|
|
+ private bool _IsGrap;
|
|
|
+ public bool IsGrap
|
|
|
+ {
|
|
|
+ get { return _IsGrap; }
|
|
|
+ set { SetProperty(ref _IsGrap, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private ObservableCollection<CameraInfo> _CameraList;
|
|
|
+ public ObservableCollection<CameraInfo> CameraList
|
|
|
+ {
|
|
|
+ get { return _CameraList; }
|
|
|
+ set { SetProperty(ref _CameraList, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private CameraInfo _SelectedCamera;
|
|
|
+ public CameraInfo SelectedCamera
|
|
|
+ {
|
|
|
+ get { return _SelectedCamera; }
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetProperty(ref _SelectedCamera, value);
|
|
|
+ if (value != null)
|
|
|
+ {
|
|
|
+ if (Camera != null)
|
|
|
+ {
|
|
|
+ if (Camera.IsGrabbing)
|
|
|
+ {
|
|
|
+ Camera.StopGrabbing();
|
|
|
+ }
|
|
|
+ Camera.ImageCallbackEvent -= Camera_ImageCallbackEvent;
|
|
|
+ }
|
|
|
+ Camera = _cameraService.GetCamera(value.Id);
|
|
|
+ Camera.ImageCallbackEvent += Camera_ImageCallbackEvent;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private ICamera _Camera;
|
|
|
+ public ICamera Camera
|
|
|
+ {
|
|
|
+ get { return _Camera; }
|
|
|
+ set { SetProperty(ref _Camera, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private ICogImage _Image;
|
|
|
|
|
|
+ public ICogImage Image
|
|
|
+ {
|
|
|
+ get { return _Image; }
|
|
|
+ set { SetProperty(ref _Image, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private string _Message;
|
|
|
+ public string Message
|
|
|
+ {
|
|
|
+ get { return _Message; }
|
|
|
+ set { SetProperty(ref _Message, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool _IsLeftDrawerOpen;
|
|
|
+ public bool IsLeftDrawerOpen
|
|
|
+ {
|
|
|
+ get { return _IsLeftDrawerOpen; }
|
|
|
+ set
|
|
|
+ {
|
|
|
+ SetProperty(ref _IsLeftDrawerOpen, value);
|
|
|
+ if (!value)
|
|
|
+ {
|
|
|
+ if (IsGrap)
|
|
|
+ {
|
|
|
+ ExecuteStopGrabbingCommand();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
#endregion
|
|
|
|
|
|
#region 命令
|
|
|
@@ -368,6 +447,13 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
private DelegateCommand _AutoCorrectLockPointCommand;
|
|
|
public DelegateCommand AutoCorrectLockPointCommand =>
|
|
|
_AutoCorrectLockPointCommand ?? (_AutoCorrectLockPointCommand = new DelegateCommand(ExecuteAutoCorrectLockPoint));
|
|
|
+ private DelegateCommand _StartGrabbingCommand;
|
|
|
+ public DelegateCommand StartGrabbingCommand =>
|
|
|
+ _StartGrabbingCommand ?? (_StartGrabbingCommand = new DelegateCommand(ExecuteStartGrabbingCommand, CanExecuteStartGrabbingCommand).ObservesProperty(() => IsGrap).ObservesProperty(() => SelectedCamera));
|
|
|
+
|
|
|
+ private DelegateCommand _StopGrabbingCommand;
|
|
|
+ public DelegateCommand StopGrabbingCommand =>
|
|
|
+ _StopGrabbingCommand ?? (_StopGrabbingCommand = new DelegateCommand(ExecuteStopGrabbingCommand, CanExecuteStopGrabbingCommand).ObservesProperty(() => IsGrap).ObservesProperty(() => SelectedCamera));
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
@@ -376,7 +462,8 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
#endregion
|
|
|
|
|
|
public PlcPointParamsViewModel(IRegionManager regionManager, IEventAggregator ea, IContainerProvider container, IDialogService dialogService,
|
|
|
- IConfigService configService, IRobotService robotService, ISystemDatabaseService systemDatabaseService, IRemoteCommandService remoteCommandService)
|
|
|
+ IConfigService configService, IRobotService robotService, ISystemDatabaseService systemDatabaseService, IRemoteCommandService remoteCommandService,
|
|
|
+ ICalibrationService calibrationService, ICameraService cameraService)
|
|
|
{
|
|
|
_regionManager = regionManager;
|
|
|
_eventAggregator = ea;
|
|
|
@@ -389,6 +476,8 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
management = _container.Resolve<Management>();
|
|
|
_robotService = robotService;
|
|
|
_remoteCommandService = remoteCommandService;
|
|
|
+ _calibrationService = calibrationService;
|
|
|
+ _cameraService = cameraService;
|
|
|
}
|
|
|
|
|
|
#region 方法
|
|
|
@@ -1115,6 +1204,285 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
_eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 通过相机先定位产品再执行锁付点位
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="point"></param>
|
|
|
+ private async Task ExecuteAutoCorrectLockPointAndExecuteCommand(PlcPoint point)
|
|
|
+ {
|
|
|
+ var waiting = new WaitingControl();
|
|
|
+ Task<object> task;
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (Robot == null || !Robot.IsConnected) return;
|
|
|
+ //弹窗提示用户是否确认要通过相机自动矫正锁附点位并执行该点位
|
|
|
+ var resultConfirm = MessageBox.Show($"确认要通过相机自动矫正锁附点位并执行点位 {point.Number} 吗?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
|
|
+ if (resultConfirm != MessageBoxResult.Yes)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (Robot == null || !Robot.IsConnected)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "机器人未连接,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //获取当前产品
|
|
|
+ var product = SelectProduct;
|
|
|
+ if (product == null)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未选择产品,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ //如果当前Local为空,则自动进行锁付点位的Local计算
|
|
|
+ if (local == null)
|
|
|
+ {
|
|
|
+ //show the dialog
|
|
|
+ task = DialogHost.Show(waiting, "RootDialog", null, null, null);
|
|
|
+ var isCalibSucceed = await AutoCalibLockPointLocal(product);
|
|
|
+ if (!isCalibSucceed)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //提示用户,当前系统检测到进入此界面后已经进行过相机产品定位并计算过Local,是否继续使用该Local进行锁付点位的转换计算
|
|
|
+ var resultUseExistingLocal = MessageBox.Show("系统检测到进入此界面后已经进行过相机产品定位并计算过Local,是否继续使用该Local进行锁付点位的转换计算?点击“是”继续使用,点击“否”则重新进行锁付点位的Local计算。", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
|
|
+ if (resultUseExistingLocal == MessageBoxResult.No)
|
|
|
+ {
|
|
|
+ //show the dialog
|
|
|
+ task = DialogHost.Show(waiting, "RootDialog", null, null, null);
|
|
|
+ var isCalibSucceed = await AutoCalibLockPointLocal(product);
|
|
|
+ if (!isCalibSucceed)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //show the dialog
|
|
|
+ task = DialogHost.Show(waiting, "RootDialog", null, null, null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //将锁付点位转换到世界坐标系
|
|
|
+ var localPoint = new PointF(point.X_Position_Start, point.Y_Position_Start);
|
|
|
+ var worldPoint = local.ToOldCoord(localPoint.X, localPoint.Y);
|
|
|
+ var point1 = point.Clone();
|
|
|
+ point1.X_Position_Start = (float)worldPoint[0];
|
|
|
+ point1.Y_Position_Start = (float)worldPoint[1];
|
|
|
+ //执行该点位
|
|
|
+ //移动机器人至拍照点位,拍照
|
|
|
+ var rpoint = new RPoint()
|
|
|
+ {
|
|
|
+ X = point.X_Position_Start,
|
|
|
+ Y = point.Y_Position_Start,
|
|
|
+ Z = point.Z_Position_Start,
|
|
|
+ };
|
|
|
+ await Robot.CalibMotionAsync(rpoint, 0);
|
|
|
+
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "完成!", Duration = 1 });
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.WriteLogError("通过相机自动矫正锁附点位并执行时出错!", ex);
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
|
|
|
+ }
|
|
|
+ finally
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ if (DialogHost.IsDialogOpen("RootDialog"))
|
|
|
+ {
|
|
|
+ DialogHost.Close("RootDialog");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ catch (Exception)
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 移动相机拍产品两个Msrk点计算Local
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="product"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ private async Task<bool> AutoCalibLockPointLocal(ProductModel product)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ //获取锁付相机拍照点位
|
|
|
+ var screwCameraPoint = product.ScrewCameraPoints;
|
|
|
+ if (screwCameraPoint == null || screwCameraPoint.Count < 2)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //获取相机拍照点位对应的锁付点
|
|
|
+ var screwCameraLocalPoint1 = product.ScrewCameraLocalPos1;
|
|
|
+ if (screwCameraLocalPoint1 == null)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位对应的锁付点,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ var screwCameraLocalPoint2 = product.ScrewCameraLocalPos2;
|
|
|
+ if (screwCameraLocalPoint2 == null)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照点位对应的锁付点,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ var ProcedureModels = new ObservableCollection<ProcedureModel>();
|
|
|
+ foreach (var item in product.CameraProcedures)
|
|
|
+ {
|
|
|
+ foreach (var item1 in item.ProcedureModels)
|
|
|
+ {
|
|
|
+ ProcedureModels.Add(item1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //获取拍照流程
|
|
|
+ if (product.MoveDownCameraLockPhotoProcedureId == Guid.Empty)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照流程,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ var procedure = ProcedureModels.FirstOrDefault(p => p.Id == product.MoveDownCameraLockPhotoProcedureId);
|
|
|
+ if (procedure == null)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "未获取到锁付相机拍照流程,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ CancellationTokenSource _cts = new CancellationTokenSource();
|
|
|
+ //移动机器人至拍照点位,拍照
|
|
|
+ var rpoint = new RPoint()
|
|
|
+ {
|
|
|
+ X = screwCameraPoint[0].X_Position_Start,
|
|
|
+ Y = screwCameraPoint[0].Y_Position_Start,
|
|
|
+ Z = screwCameraPoint[0].Z_Position_Start,
|
|
|
+ U = screwCameraPoint[0].U_Position_Start,
|
|
|
+ V = screwCameraPoint[0].R_Position,
|
|
|
+ };
|
|
|
+ await Robot.CalibMotionAsync(rpoint, 0);
|
|
|
+ await Task.Delay(200);
|
|
|
+ // 执行拍照并获取识别结果
|
|
|
+ var recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePointWithImage(procedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
|
|
|
+ //var Image = recognitionResult.Image;
|
|
|
+ //var Graphic = null;
|
|
|
+ //var Graphic = recognitionResult.Graphic;
|
|
|
+ if (!recognitionResult.IsSucceed)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "拍照获取识别结果失败,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //第一个点位的校正结果
|
|
|
+ PointF worldP1 = new PointF((float)recognitionResult.X, (float)recognitionResult.Y);
|
|
|
+ //移动机器人至拍照点位,拍照
|
|
|
+ rpoint = new RPoint()
|
|
|
+ {
|
|
|
+ X = screwCameraPoint[1].X_Position_Start,
|
|
|
+ Y = screwCameraPoint[1].Y_Position_Start,
|
|
|
+ Z = screwCameraPoint[1].Z_Position_Start,
|
|
|
+ U = screwCameraPoint[1].U_Position_Start,
|
|
|
+ V = screwCameraPoint[1].R_Position,
|
|
|
+ };
|
|
|
+ await Robot.CalibMotionAsync(rpoint, 0);
|
|
|
+ if (_cts.IsCancellationRequested)
|
|
|
+ return false;
|
|
|
+ await Task.Delay(200);
|
|
|
+ // 执行拍照并获取识别结果
|
|
|
+ recognitionResult = await _remoteCommandService.ExecutePhotoGetSinglePointWithImage(procedure, null, new double[] { rpoint.X, rpoint.Y, 0 }, _cts.Token);
|
|
|
+ //Image = recognitionResult.Image;
|
|
|
+ //Graphic = null;
|
|
|
+ //Graphic = recognitionResult.Graphic;
|
|
|
+ if (!recognitionResult.IsSucceed)
|
|
|
+ {
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = "拍照获取识别结果失败,无法执行取料拍照点位矫正!", Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ //第一个点位的校正结果
|
|
|
+ PointF worldP2 = new PointF((float)recognitionResult.X, (float)recognitionResult.Y);
|
|
|
+
|
|
|
+ //计算移动相机与拍照点之间的偏差
|
|
|
+ //获取校准
|
|
|
+ var calibration = _calibrationService.GetCalibration(procedure.CalibrationId);
|
|
|
+
|
|
|
+ //获取mark点
|
|
|
+ var mark = calibration.MarkPoint;
|
|
|
+ //获取中心点
|
|
|
+ var center = calibration.CenterPoint;
|
|
|
+ //计算相机中心与披头之间的坐标偏差
|
|
|
+ var cameraOffsetX = mark.X - center.X;
|
|
|
+ var cameraOffsetY = mark.Y - center.Y;
|
|
|
+
|
|
|
+
|
|
|
+ //根据UpCameraPutResults[]中的索引1、2,和拍照点对应的Local下的坐标,从创建Local坐标系
|
|
|
+ PointF localP1 = new PointF(screwCameraLocalPoint1.X_Position_Start, screwCameraLocalPoint1.Y_Position_Start);
|
|
|
+ PointF localP2 = new PointF(screwCameraLocalPoint2.X_Position_Start, screwCameraLocalPoint2.Y_Position_Start);
|
|
|
+ local = new CoordinateTransformer(worldP1, worldP2, localP1, localP2);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ LogHelper.WriteLogError("计算锁付点位产品坐标系坐标时出错!", ex);
|
|
|
+ _eventAggregator.GetEvent<SnackbarMessageNotification>().Publish(new MessageParameter() { Msg = ex.Message, Duration = 1 });
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 停止采集
|
|
|
+ /// </summary>
|
|
|
+ void ExecuteStopGrabbingCommand()
|
|
|
+ {
|
|
|
+
|
|
|
+ if (Camera != null)
|
|
|
+ Camera.StopGrabbing();
|
|
|
+ IsGrap = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool CanExecuteStopGrabbingCommand()
|
|
|
+ {
|
|
|
+ return IsGrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// 开始采集
|
|
|
+ /// </summary>
|
|
|
+ void ExecuteStartGrabbingCommand()
|
|
|
+ {
|
|
|
+ if (Camera != null)
|
|
|
+ Camera.StartGrabbing();
|
|
|
+ IsGrap = true;
|
|
|
+ }
|
|
|
+ bool CanExecuteStartGrabbingCommand()
|
|
|
+ {
|
|
|
+ return SelectedCamera != null && !IsGrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Camera_ImageCallbackEvent(ICogImage image, TimeSpan totaltime, string errormessage)
|
|
|
+ {
|
|
|
+ Image = image;
|
|
|
+ App.Current.Dispatcher.Invoke(new
|
|
|
+ Action(() =>
|
|
|
+ {
|
|
|
+ if (errormessage != null && !string.IsNullOrEmpty(errormessage))
|
|
|
+ {
|
|
|
+ Message = $"{Lang.耗时}:{totaltime.TotalMilliseconds.ToString("F1")} ms Error:{errormessage}";
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Message = $"{Lang.耗时}:{totaltime.TotalMilliseconds.ToString("F1")} ms";
|
|
|
+ }
|
|
|
+ }));
|
|
|
+ }
|
|
|
#endregion
|
|
|
|
|
|
#region 继承
|
|
|
@@ -1139,9 +1507,14 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
{
|
|
|
SelectProduct = navigationContext.Parameters.GetValue<ProductModel>("SelectProduct");
|
|
|
|
|
|
- SelectedIndex = 0;
|
|
|
+
|
|
|
+ // 默认选择 AOI 点位(索引 6),并初始化 Points
|
|
|
+ SelectedIndex = 6;
|
|
|
PickPoints = SelectProduct.PickPoints;
|
|
|
- Points = SelectProduct.PickCameraPoints;
|
|
|
+ Points = SelectProduct.AoiPoints;
|
|
|
+ // 默认选中第一个点(如果存在)
|
|
|
+ SelectedPointInDataGrid = Points?.FirstOrDefault();
|
|
|
+ SelectedPointInComboBox = SelectedPointInDataGrid;
|
|
|
|
|
|
if (Robot == null)
|
|
|
{
|
|
|
@@ -1175,6 +1548,8 @@ namespace TeamAAS_VP.ViewModels.Product
|
|
|
LockZDescendSpeed= SelectProduct.ScrewPoints.FirstOrDefault()?.Z_Velocity_Stop ?? 100;
|
|
|
LockFeederNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.Feeder ?? 1;
|
|
|
LockScrewProgramNumber= SelectProduct.ScrewPoints.FirstOrDefault()?.ScrewProNum ?? 1;
|
|
|
+
|
|
|
+ CameraList = new ObservableCollection<CameraInfo>(_configService.GetAllCameras());
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|