using System.Collections.ObjectModel; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Input; namespace SHH.CameraDashboard { public class CameraImageSubscriptionViewModels : INotifyPropertyChanged { private readonly WebApiCameraModel _camera; public event Action RequestClose; // 用于绑定 ComboBox 的类型列表 public Dictionary SubscriptionTypes { get; } = new Dictionary { { 0, "本地窗口预览" }, { 1, "本地录像" }, { 2, "句柄渲染 (嵌入)" }, { 3, "网络转发 (TCP/UDP)" }, { 4, "Web 推流" } }; // --- 数据源 --- public ObservableCollection Subscriptions { get; set; } = new ObservableCollection(); // --- 编辑表单属性 --- private string _editAppId; public string EditAppId { get => _editAppId; set { _editAppId = value; OnPropertyChanged(); } } private int _editType; public int EditType { get => _editType; set { _editType = value; OnPropertyChanged(); // 切换类型时,控制 UI 上 IP/Port 输入框的显示 OnPropertyChanged(nameof(IsNetworkType)); OnPropertyChanged(nameof(IsRecordType)); } } private int _editFps = 25; public int EditFps { get => _editFps; set { _editFps = value; OnPropertyChanged(); } } private string _editMemo; public string EditMemo { get => _editMemo; set { _editMemo = value; OnPropertyChanged(); } } // 网络参数 private string _editTargetIp = "127.0.0.1"; public string EditTargetIp { get => _editTargetIp; set { _editTargetIp = value; OnPropertyChanged(); } } private int _editTargetPort = 8080; public int EditTargetPort { get => _editTargetPort; set { _editTargetPort = value; OnPropertyChanged(); } } // --- 界面显隐控制 --- // 只有类型是 3或4 时显示网络设置 public bool IsNetworkType => EditType == 3 || EditType == 4; // 只有类型是 1 时显示录像设置 (这里简化,暂时只演示网络显隐) public bool IsRecordType => EditType == 1; // --- 命令 --- public ICommand LoadCommand { get; } public ICommand SaveCommand { get; } public ICommand DeleteCommand { get; } public ICommand ClearFormCommand { get; } public CameraImageSubscriptionViewModels(WebApiCameraModel camera) { _camera = camera; LoadCommand = new RelayCommand(ExecuteLoad); SaveCommand = new RelayCommand(ExecuteSave); DeleteCommand = new RelayCommand(ExecuteDelete); ClearFormCommand = new RelayCommand(obj => ResetForm()); // 初始化加载 ExecuteLoad(null); } private async void ExecuteLoad(object obj) { var list = await ApiClient.Instance.Cameras.GetSubscriptionsAsync(_camera.Id); Subscriptions.Clear(); foreach (var item in list) { Subscriptions.Add(item); } } private async void ExecuteSave(object obj) { // 1. 基础校验 if (string.IsNullOrWhiteSpace(EditAppId)) { MessageBox.Show("AppId 不能为空", "提示"); return; } // 2. 构建 DTO // 注意:这里需要根据你 DTO 的定义进行类型转换和默认值处理 var dto = new SubscriptionDto { AppId = EditAppId, // ★★★ 修改:直接赋值 int,不需要强转枚举 ★★★ Type = EditType, DisplayFps = EditFps, Memo = EditMemo ?? string.Empty, // ... 网络参数 ... TargetIp = IsNetworkType ? (EditTargetIp ?? string.Empty) : string.Empty, TargetPort = IsNetworkType ? EditTargetPort : 0, // ★★★ 修改:直接赋值 int ★★★ Protocol = 0, // 0 代表 TCP // ... 其他参数 ... Handle = string.Empty, SavePath = ((SubscriptionType)EditType == SubscriptionType.LocalRecord) ? @"C:\Temp\Video" : string.Empty, RecordDuration = 0 }; // 3. 发送请求 bool success = await ApiClient.Instance.Cameras.UpdateSubscriptionAsync(_camera.Id, dto); if (success) { MessageBox.Show("保存成功", "提示"); ExecuteLoad(null); // 刷新列表 // ResetForm(); // 可选:保存后清空表单 } else { MessageBox.Show("保存失败,请检查网络或参数。", "错误"); } } private async void ExecuteDelete(object parameter) { // 支持两种方式删除: // 1. 传入 parameter (点击列表中的删除按钮) // 2. 根据当前表单的 AppId (如果在编辑模式) string appIdToDelete = parameter as string; if (string.IsNullOrEmpty(appIdToDelete)) return; if (MessageBox.Show($"确定要停止并注销 [{appIdToDelete}] 吗?", "确认", MessageBoxButton.YesNo) != MessageBoxResult.Yes) return; // 构造删除请求:关键是 DisplayFps = 0 var dto = new SubscriptionDto { AppId = appIdToDelete, Type = 0, DisplayFps = 0, // <--- 核心:0 代表注销 Memo = "User Deleted" }; bool success = await ApiClient.Instance.Cameras.UpdateSubscriptionAsync(_camera.Id, dto); if (success) { ExecuteLoad(null); } } private void ResetForm() { // 生成一个随机 AppId 方便测试 EditAppId = $"Client_{DateTime.Now:HHmmss}"; EditType = 0; EditFps = 25; EditMemo = ""; EditTargetIp = "127.0.0.1"; EditTargetPort = 8080; } // --- INotifyPropertyChanged 实现 (略,使用你的基类或标准实现) --- public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } // 1. 添加一个字段 private SubscriptionDto _selectedSubscription; // 2. 添加 SelectedSubscription 属性 public SubscriptionDto SelectedSubscription { get => _selectedSubscription; set { // 如果两次选中同一个,不做处理 if (_selectedSubscription == value) return; _selectedSubscription = value; OnPropertyChanged(); // ★★★ 核心逻辑:一旦选中项发生变化,就填充表单 ★★★ if (_selectedSubscription != null) { FillForm(_selectedSubscription); } } } // 3. 编写填充表单的辅助方法 private void FillForm(SubscriptionDto dto) { // 这里我们将 DTO 的值“复制”到编辑属性中 // 这样做的好处是:修改下方文本框时,不会立即改变列表里的显示,只有点击“保存”后才刷新 EditAppId = dto.AppId; EditType = dto.Type; // 之前改成了 int,直接赋值即可 EditFps = dto.DisplayFps; // 注意:后端返回可能是 targetFps,前端 DTO 映射已修复 EditMemo = dto.Memo; // 网络参数回显 EditTargetIp = dto.TargetIp; EditTargetPort = dto.TargetPort; // 触发一下 UI 状态刷新(比如网络参数的显隐) OnPropertyChanged(nameof(IsNetworkType)); } } }