using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Input; namespace SHH.CameraDashboard { public class CameraEditViewModel : INotifyPropertyChanged { // 编辑中的数据副本 private CameraEditInfo _editingDto; // 定义一个事件,通知 View 关闭窗口(或者 UserControl 所在的宿主) public event Action RequestClose; public CameraEditInfo EditingDto { get => _editingDto; set { _editingDto = value; OnPropertyChanged(); } } public ICommand SaveCommand { get; } public ICommand CancelCommand { get; } private bool _isAdd = false; /// /// 构造函数 /// /// 如果是编辑模式,传入源对象;如果是新增,传入 null public CameraEditViewModel(CameraEditInfo sourceDto = null) { // 初始化枚举列表 InitBrandOptions(); if (sourceDto != null) { // 编辑模式:深拷贝数据,避免直接修改源对象 EditingDto = CloneDto(sourceDto); } else { // 新增模式:创建默认对象 EditingDto = new CameraEditInfo { Name = "新设备", Port = 8000, ChannelIndex = 1 }; } if (EditingDto.Id == 0) _isAdd = true; SaveCommand = new RelayCommand(ExecuteSave, CanSave); CancelCommand = new RelayCommand(ExecuteCancel); } private bool CanSave(object obj) { // 简单验证:ID必须大于0,IP不能为空 if (EditingDto == null) return false; return EditingDto.Id > 0 && !string.IsNullOrWhiteSpace(EditingDto.IpAddress); } private bool IsSaving; private async void ExecuteSave(object obj) { if (IsSaving) return; try { IsSaving = true; // 开启 Loading bool isSuccess = false; if (_isAdd) { isSuccess = await ApiClient.Instance.Cameras.CreateCameraAsync(EditingDto, "摄像头-新增"); } else { isSuccess = await ApiClient.Instance.Cameras.UpdateCameraAsync(EditingDto, "摄像头-编辑"); _isAdd = false; } // 1. 调用 Repository (ApiClient) // 注意:这里调用的是我们刚才在 Repository 中定义的 UpdateCameraAsync if (isSuccess) { // 2. 成功:通知外部关闭面板,并刷新列表 RequestClose?.Invoke(true, EditingDto); } else { // 3. 失败:弹窗提示 MessageBox.Show("保存失败,请检查服务节点日志。", "系统提示", MessageBoxButton.OK, MessageBoxImage.Error); } } catch (Exception ex) { MessageBox.Show($"保存过程中发生异常:\n{ex.Message}", "系统错误", MessageBoxButton.OK, MessageBoxImage.Error); } finally { IsSaving = false; // 关闭 Loading } } private void ExecuteCancel(object obj) { // false 表示取消操作 RequestClose?.Invoke(false, null); } /// /// 手动深拷贝 DTO,防止引用传递导致界面未点保存就修改了列表 /// 生产环境建议用 AutoMapper 或 JSON 序列化实现 /// private CameraEditInfo CloneDto(CameraEditInfo source) { return new CameraEditInfo { Id = source.Id, Name = source.Name, Brand = source.Brand, Location = source.Location, IpAddress = source.IpAddress, Port = source.Port, Username = source.Username, Password = source.Password, RenderHandle = source.RenderHandle, ChannelIndex = source.ChannelIndex, RtspPath = source.RtspPath, MainboardIp = source.MainboardIp, MainboardPort = source.MainboardPort, StreamType = source.StreamType, UseGrayscale = source.UseGrayscale, EnhanceImage = source.EnhanceImage, AllowCompress = source.AllowCompress, AllowExpand = source.AllowExpand, TargetResolution = source.TargetResolution }; } public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); // 1. 定义一个简单的内部类或结构,用于 ComboBox 显示 public class BrandOption { public string Label { get; set; } // 显示的文本 (Description) public int Value { get; set; } // 实际的值 (int) } // 2. 数据源属性 public List BrandOptions { get; private set; } private void InitBrandOptions() { // 遍历 DeviceBrand 枚举的所有值 BrandOptions = Enum.GetValues(typeof(DeviceBrand)) .Cast() .Select(e => new BrandOption { // 获取 Description ("海康威视") Label = EnumHelper.GetDescription(e), // 获取 int 值 (1) Value = (int)e }) .ToList(); } } }