using System; using System.ComponentModel; using System.Runtime.CompilerServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Input; namespace SHH.CameraDashboard { public class CameraImgProcViewModel : INotifyPropertyChanged { private readonly WebApiCameraModel _sourceCamera; private readonly CameraEditInfo _editInfo; public event Action RequestClose; public string Title => $"{_sourceCamera.Name} - 图像处理"; public string SourceResolutionText => $"{_sourceCamera.Width} x {_sourceCamera.Height}"; // --- 状态控制属性 --- // 源是否是高清 (>= 1080P) public bool IsSourceHighRes => _sourceCamera.Width >= 1920 || _sourceCamera.Height >= 1080; // 是否允许勾选“允许放大” (UI 绑定 IsEnabled) public bool CanCheckExpand => !IsSourceHighRes; // 滑块是否可用 (只有开启了缩小 或 开启了放大,才允许拖动) // ★★★ 修正:使用 AllowEnlarge ★★★ public bool IsSliderEnabled => AllowShrink || AllowEnlarge; // 允许缩小 public bool AllowShrink { get => _editInfo.AllowShrink; set { if (_editInfo.AllowShrink != value) { _editInfo.AllowShrink = value; OnPropertyChanged(); OnPropertyChanged(nameof(IsSliderEnabled)); ValidateAndSyncSlider(); } } } // ★★★ 修正:属性名为 AllowEnlarge,对应 Model 中的 AllowEnlarge ★★★ public bool AllowEnlarge { get => _editInfo.AllowEnlarge; set { if (_editInfo.AllowEnlarge != value) { _editInfo.AllowEnlarge = value; OnPropertyChanged(); OnPropertyChanged(nameof(IsSliderEnabled)); // 开关变化时,重新校验当前尺寸是否合法 ValidateAndSyncSlider(); } } } // 图像增强 public bool EnhanceImage { get => _editInfo.EnhanceImage; set { if (_editInfo.EnhanceImage != value) { _editInfo.EnhanceImage = value; OnPropertyChanged(); } } } // --- 分辨率与缩放属性 --- private int _targetWidth; public int TargetWidth { get => _targetWidth; set { if (SetProperty(ref _targetWidth, value)) { if (IsRatioLocked && _sourceCamera.Width > 0) { _targetHeight = (int)((double)value / _sourceCamera.Width * _sourceCamera.Height); OnPropertyChanged(nameof(TargetHeight)); } ValidateAndSyncSlider(); } } } private int _targetHeight; public int TargetHeight { get => _targetHeight; set { if (SetProperty(ref _targetHeight, value)) { if (IsRatioLocked && _sourceCamera.Height > 0) { _targetWidth = (int)((double)value / _sourceCamera.Height * _sourceCamera.Width); OnPropertyChanged(nameof(TargetWidth)); } ValidateAndSyncSlider(); } } } private bool _isRatioLocked = true; public bool IsRatioLocked { get => _isRatioLocked; set => SetProperty(ref _isRatioLocked, value); } private double _scalePercent = 100; public double ScalePercent { get => _scalePercent; set { if (SetProperty(ref _scalePercent, value)) { UpdateResolutionByScale(value); } } } // [新增] 亮度调节属性 public int Brightness { get => _editInfo.Brightness; set { if (_editInfo.Brightness != value) { _editInfo.Brightness = value; OnPropertyChanged(); // 如果需要,可以在这里限制范围,例如 0-100 } } } public ICommand SaveCommand { get; } public ICommand CancelCommand { get; } public ICommand ApplyPresetCommand { get; } public CameraImgProcViewModel(WebApiCameraModel source, CameraEditInfo detail) { _sourceCamera = source; // 此时 detail 可能是不完整的,先赋值防止空引用 _editInfo = detail ?? new CameraEditInfo { Id = source.Id }; SaveCommand = new RelayCommand(ExecuteSave); CancelCommand = new RelayCommand(o => RequestClose?.Invoke()); ApplyPresetCommand = new RelayCommand(ExecutePreset); InitializeState(); LoadDataAsync(); } // 2. 实现加载逻辑 private async void LoadDataAsync() { // 调用 Repository var remoteInfo = await ApiClient.Instance.Cameras.GetImageProcessingAsync(_sourceCamera.Id); if (remoteInfo != null) { // --- A. 更新 ViewModel 的开关属性 --- // 注意:Setter 会自动触发 OnPropertyChanged 和 ValidateAndSyncSlider AllowShrink = remoteInfo.AllowShrink; AllowEnlarge = remoteInfo.AllowEnlarge; // 这里会自动更新 IsSliderEnabled EnhanceImage = remoteInfo.EnhanceImage; // --- B. 更新分辨率 (解析 "W x H") --- if (!string.IsNullOrWhiteSpace(remoteInfo.TargetResolution)) { var parts = remoteInfo.TargetResolution.Split('x'); if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h)) { // 赋值 TargetWidth/Height 会自动触发 ValidateAndSyncSlider // 从而更新 ScalePercent 和 滑块位置 TargetWidth = w; TargetHeight = h; } } } } private void InitializeState() { // 1. 强制规则:如果源分辨率 >= 1080P,不允许放大 if (IsSourceHighRes) { _editInfo.AllowEnlarge = false; // ★★★ 修正引用 ★★★ } // 2. 检查历史设置 // ★★★ 修正引用 ★★★ bool hasPreviousSettings = _editInfo.AllowShrink || _editInfo.AllowEnlarge; if (hasPreviousSettings) { if (!string.IsNullOrWhiteSpace(_editInfo.TargetResolution)) { var parts = _editInfo.TargetResolution.ToLower().Split('x'); if (parts.Length == 2 && int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h)) { _targetWidth = w; _targetHeight = h; } } } else { // 默认逻辑 if (_sourceCamera.Width > 1280) { _targetWidth = 1280; _targetHeight = _sourceCamera.Width > 0 ? (int)((double)1280 / _sourceCamera.Width * _sourceCamera.Height) : 720; } else { _targetWidth = _sourceCamera.Width; _targetHeight = _sourceCamera.Height; } } ValidateAndSyncSlider(); } private void UpdateResolutionByScale(double percent) { if (_sourceCamera.Width <= 0 || _sourceCamera.Height <= 0) return; double w = _sourceCamera.Width * (percent / 100.0); double h = _sourceCamera.Height * (percent / 100.0); _targetWidth = (int)w; _targetHeight = (int)h; OnPropertyChanged(nameof(TargetWidth)); OnPropertyChanged(nameof(TargetHeight)); } private void ValidateAndSyncSlider() { if (_sourceCamera.Width <= 0) return; // ★★★ 修正引用:使用 AllowEnlarge ★★★ int maxWidth = AllowEnlarge ? 1920 : _sourceCamera.Width; int maxHeight = AllowEnlarge ? 1080 : _sourceCamera.Height; int minWidth = 160; bool changed = false; // 规则A:如果未开启放大,且当前 > 源 -> 强制回退到源 // ★★★ 修正引用 ★★★ if (!AllowEnlarge && (_targetWidth > _sourceCamera.Width)) { _targetWidth = _sourceCamera.Width; _targetHeight = _sourceCamera.Height; changed = true; } if (!AllowShrink && (_targetWidth < _sourceCamera.Width)) { _targetWidth = _sourceCamera.Width; _targetHeight = _sourceCamera.Height; changed = true; } if (_targetWidth > 1920) { _targetWidth = 1920; changed = true; } if (_targetHeight > 1080) { _targetHeight = 1080; changed = true; } if (_targetWidth < minWidth) { _targetWidth = minWidth; changed = true; } if (changed) { OnPropertyChanged(nameof(TargetWidth)); OnPropertyChanged(nameof(TargetHeight)); } double currentPercent = ((double)_targetWidth / _sourceCamera.Width) * 100.0; if (Math.Abs(_scalePercent - currentPercent) > 0.1) { _scalePercent = currentPercent; OnPropertyChanged(nameof(ScalePercent)); } } private void ExecutePreset(object parameter) { if (parameter is string preset) { var parts = preset.Split('x'); if (parts.Length != 2) return; if (int.TryParse(parts[0], out int w) && int.TryParse(parts[1], out int h)) { if (w > _sourceCamera.Width) { if (IsSourceHighRes) { MessageBox.Show("当前源分辨率已超过或等于 1080P,不支持放大。", "提示"); return; } AllowEnlarge = true; // ★★★ 修正引用 ★★★ } else if (w < _sourceCamera.Width) { AllowShrink = true; } TargetWidth = w; TargetHeight = h; IsRatioLocked = true; } } } private async void ExecuteSave(object obj) { // 1. 准备数据 (拼接分辨率字符串) _editInfo.TargetResolution = $"{TargetWidth}x{TargetHeight}"; // 2. 调用专用的 Processing 接口 bool success = await ApiClient.Instance.Cameras.UpdateImageProcessingAsync(_editInfo); // <--- 换成这就行 if (success) { AppGlobal.RequestRefresh(); RequestClose?.Invoke(); } else { MessageBox.Show("保存图像处理配置失败,请检查网络或后端日志。", "错误"); } } public event PropertyChangedEventHandler PropertyChanged; protected bool SetProperty(ref T field, T value, [CallerMemberName] string name = null) { if (Equals(field, value)) return false; field = value; OnPropertyChanged(name); return true; } protected void OnPropertyChanged([CallerMemberName] string name = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } }