具备界面基础功能
This commit is contained in:
369
SHH.CameraDashboard/ViewModels/CameraImgProcViewModel.cs
Normal file
369
SHH.CameraDashboard/ViewModels/CameraImgProcViewModel.cs
Normal file
@@ -0,0 +1,369 @@
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user