具备界面基础功能
This commit is contained in:
177
SHH.CameraDashboard/ViewModels/CameraEditViewModel.cs
Normal file
177
SHH.CameraDashboard/ViewModels/CameraEditViewModel.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
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<bool, CameraEditInfo> RequestClose;
|
||||
|
||||
public CameraEditInfo EditingDto
|
||||
{
|
||||
get => _editingDto;
|
||||
set { _editingDto = value; OnPropertyChanged(); }
|
||||
}
|
||||
|
||||
public ICommand SaveCommand { get; }
|
||||
public ICommand CancelCommand { get; }
|
||||
|
||||
private bool _isAdd = false;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="sourceDto">如果是编辑模式,传入源对象;如果是新增,传入 null</param>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动深拷贝 DTO,防止引用传递导致界面未点保存就修改了列表
|
||||
/// 生产环境建议用 AutoMapper 或 JSON 序列化实现
|
||||
/// </summary>
|
||||
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<BrandOption> BrandOptions { get; private set; }
|
||||
|
||||
private void InitBrandOptions()
|
||||
{
|
||||
// 遍历 DeviceBrand 枚举的所有值
|
||||
BrandOptions = Enum.GetValues(typeof(DeviceBrand))
|
||||
.Cast<DeviceBrand>()
|
||||
.Select(e => new BrandOption
|
||||
{
|
||||
// 获取 Description ("海康威视")
|
||||
Label = EnumHelper.GetDescription(e),
|
||||
// 获取 int 值 (1)
|
||||
Value = (int)e
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user