Files
Ayay/SHH.CameraDashboard/ViewModels/CameraImgProcViewModel.cs

369 lines
12 KiB
C#
Raw Permalink Normal View History

2026-01-01 22:40:32 +08:00
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<T>(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));
}
}
}