NavisworksTransport/src/UI/WPF/Models/PathRouteViewModel.cs

826 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
using System.Linq;
using NavisworksTransport.Core;
namespace NavisworksTransport.UI.WPF.ViewModels
{
/// <summary>
/// 路径点数据类 (UI ViewModel)
/// 已重构为线程安全的ViewModel继承自ViewModelBase
/// </summary>
public class PathPointViewModel : ViewModelBase
{
private string _id;
private double _x;
private double _y;
private double _z;
private string _name;
private NavisworksTransport.PathPointType _type; // 使用完全限定名
private int _index; // 路径点在列表中的索引
/// <summary>
/// 路径点ID
/// </summary>
public string Id
{
get => _id;
set => SetProperty(ref _id, value);
}
/// <summary>
/// X坐标
/// </summary>
public double X
{
get => _x;
set
{
if (SetProperty(ref _x, value))
{
OnPropertyChanged(nameof(CoordinateString));
}
}
}
/// <summary>
/// Y坐标
/// </summary>
public double Y
{
get => _y;
set
{
if (SetProperty(ref _y, value))
{
OnPropertyChanged(nameof(CoordinateString));
}
}
}
/// <summary>
/// Z坐标
/// </summary>
public double Z
{
get => _z;
set
{
if (SetProperty(ref _z, value))
{
OnPropertyChanged(nameof(CoordinateString));
}
}
}
/// <summary>
/// 点名称
/// </summary>
public string Name
{
get => _name;
set => SetProperty(ref _name, value);
}
/// <summary>
/// 点类型
/// </summary>
public NavisworksTransport.PathPointType Type // 使用完全限定名
{
get => _type;
set
{
if (SetProperty(ref _type, value))
{
// 当Type变更时自动触发TypeDisplayString的更新
OnPropertyChanged(nameof(TypeDisplayString));
}
}
}
/// <summary>
/// 点类型的显示字符串
/// </summary>
public string TypeDisplayString
{
get
{
switch (Type)
{
case NavisworksTransport.PathPointType.StartPoint:
return "起点";
case NavisworksTransport.PathPointType.EndPoint:
return "终点";
default:
return "途经点";
}
}
}
/// <summary>
/// 路径点在列表中的索引
/// </summary>
public int Index
{
get => _index;
set => SetProperty(ref _index, value);
}
/// <summary>
/// 坐标字符串表示
/// </summary>
public string CoordinateString => $"({X:F2}, {Y:F2}, {Z:F2})";
#region
/// <summary>
/// 初始化PathPointViewModel
/// </summary>
public PathPointViewModel() : base()
{
// 设置默认值
_id = Guid.NewGuid().ToString();
_name = "路径点";
_type = NavisworksTransport.PathPointType.WayPoint;
_x = 0.0;
_y = 0.0;
_z = 0.0;
}
/// <summary>
/// 使用指定参数初始化PathPointViewModel
/// </summary>
/// <param name="name">点名称</param>
/// <param name="x">X坐标</param>
/// <param name="y">Y坐标</param>
/// <param name="z">Z坐标</param>
/// <param name="type">点类型</param>
public PathPointViewModel(string name, double x, double y, double z, NavisworksTransport.PathPointType type = NavisworksTransport.PathPointType.WayPoint) : base()
{
_id = Guid.NewGuid().ToString();
_name = name ?? "路径点";
_x = x;
_y = y;
_z = z;
_type = type;
}
#endregion
}
/// <summary>
/// 路径视图模型类 - 用于WPF数据绑定
/// 已重构为线程安全的ViewModel集成UIStateManager和ThreadSafeObservableCollection
/// </summary>
public class PathRouteViewModel : ViewModelBase
{
#region
private PathRoute _route; // 核心路径对象引用
private string _id;
private string _name;
private ObservableCollection<PathPointViewModel> _points;
private bool _isActive;
private string _description;
private DateTime _createdTime;
private DateTime _lastModifiedTime;
private bool _isValidated;
private string _validationStatus;
private PathType _pathType;
// UI状态管理
private readonly UIStateManager _uiStateManager;
private bool _isInitialized = false;
#endregion
#region
/// <summary>
/// 核心路径对象(直接引用,避免数据重复)
/// </summary>
public PathRoute Route
{
get => _route;
set
{
if (SetProperty(ref _route, value))
{
// Route变化时通知所有从Route读取的属性更新
OnPropertyChanged(nameof(Id));
OnPropertyChanged(nameof(Name));
OnPropertyChanged(nameof(Description));
OnPropertyChanged(nameof(PathType));
OnPropertyChanged(nameof(TotalLength));
OnPropertyChanged(nameof(CreatedTime));
OnPropertyChanged(nameof(LastModifiedTime));
}
}
}
/// <summary>
/// 路径ID
/// </summary>
public string Id
{
get => Route?.Id ?? _id;
set => SetProperty(ref _id, value);
}
/// <summary>
/// 路径名称
/// </summary>
public string Name
{
get => Route?.Name ?? _name;
set
{
if (SetProperty(ref _name, value))
{
_lastModifiedTime = DateTime.Now;
OnPropertyChanged(nameof(LastModifiedTime));
}
}
}
/// <summary>
/// 路径点集合
/// </summary>
public ObservableCollection<PathPointViewModel> Points
{
get => _points;
private set => SetProperty(ref _points, value);
}
/// <summary>
/// 是否为活动路径
/// </summary>
public bool IsActive
{
get => _isActive;
set
{
if (SetProperty(ref _isActive, value))
{
_lastModifiedTime = DateTime.Now;
OnPropertyChanged(nameof(LastModifiedTime));
OnPropertyChanged(nameof(StatusString));
}
}
}
/// <summary>
/// 路径描述
/// </summary>
public string Description
{
get => Route?.Description ?? _description;
set
{
if (SetProperty(ref _description, value))
{
_lastModifiedTime = DateTime.Now;
OnPropertyChanged(nameof(LastModifiedTime));
}
}
}
/// <summary>
/// 路径点数量
/// </summary>
public int PointCount => Points?.Count ?? 0;
/// <summary>
/// 路径类型
/// </summary>
public NavisworksTransport.PathType PathType
{
get => Route?.PathType ?? _pathType;
set => SetProperty(ref _pathType, value);
}
/// <summary>
/// 空中路径子类型(仅当 PathType == Aerial 时有效)
/// </summary>
public NavisworksTransport.AerialSubType AerialSubType { get; set; } = NavisworksTransport.AerialSubType.Rail;
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreatedTime
{
get => Route?.CreatedTime ?? _createdTime;
private set => SetProperty(ref _createdTime, value);
}
/// <summary>
/// 最后修改时间
/// </summary>
public DateTime LastModifiedTime
{
get => Route?.LastModified ?? _lastModifiedTime;
private set => SetProperty(ref _lastModifiedTime, value);
}
/// <summary>
/// 设置时间信息(用于从数据库加载)
/// </summary>
public void SetTimeInfo(DateTime createdTime, DateTime lastModifiedTime)
{
_createdTime = createdTime;
_lastModifiedTime = lastModifiedTime;
OnPropertyChanged(nameof(CreatedTime));
OnPropertyChanged(nameof(LastModifiedTime));
}
/// <summary>
/// 路径总长度(米)
/// </summary>
public double TotalLength
{
get => Route?.TotalLength ?? 0.0;
}
/// <summary>
/// 是否已验证
/// </summary>
public bool IsValidated
{
get => _isValidated;
private set => SetProperty(ref _isValidated, value);
}
/// <summary>
/// 验证状态描述
/// </summary>
public string ValidationStatus
{
get => _validationStatus;
private set => SetProperty(ref _validationStatus, value);
}
/// <summary>
/// 路径状态字符串
/// </summary>
public string StatusString => IsActive ? "活动" : "非活动";
/// <summary>
/// 路径摘要信息
/// </summary>
public string SummaryInfo => $"{Name} - {PointCount}个点 - {TotalLength:F2}m - {StatusString}";
/// <summary>
/// 是否已初始化
/// </summary>
public bool IsInitialized => _isInitialized;
#endregion
#region
/// <summary>
/// 默认构造函数(用于新建路径)
/// </summary>
public PathRouteViewModel() : this(isFromDatabase: false)
{
}
/// <summary>
/// 构造函数,控制是否从数据库加载
/// </summary>
/// <param name="isFromDatabase">是否从数据库/内存加载false表示新建路径</param>
public PathRouteViewModel(bool isFromDatabase)
{
try
{
// 获取UI状态管理器实例
_uiStateManager = UIStateManager.Instance;
// 验证关键组件
if (_uiStateManager == null)
{
LogManager.Error("UIStateManager初始化失败");
throw new InvalidOperationException("UIStateManager初始化失败");
}
// 根据场景选择初始化方式
if (!isFromDatabase)
{
InitializeDefaultsForNewRoute();
}
else
{
InitializeMinimal();
}
// 直接完成初始化,不需要异步
CompleteInitialization();
LogManager.Debug($"PathRouteViewModel构造函数完成{_name}");
}
catch (Exception ex)
{
LogManager.Error($"PathRouteViewModel构造函数异常: {ex.Message}", ex);
throw;
}
}
/// <summary>
/// 使用指定名称构造(用于新建路径)
/// </summary>
/// <param name="name">路径名称</param>
public PathRouteViewModel(string name) : this()
{
_name = name ?? "新路径";
}
/// <summary>
/// 使用完整参数构造(用于新建路径)
/// </summary>
/// <param name="name">路径名称</param>
/// <param name="description">路径描述</param>
public PathRouteViewModel(string name, string description) : this()
{
_name = name ?? "新路径";
_description = description ?? "";
}
/// <summary>
/// 最小化初始化(用于从数据库/内存加载路径)
/// </summary>
private void InitializeMinimal()
{
_id = string.Empty;
_name = string.Empty;
_description = string.Empty;
_isActive = false;
_createdTime = DateTime.MinValue;
_lastModifiedTime = DateTime.MinValue;
_isValidated = false;
_validationStatus = "未验证";
// 初始化点集合
Points = new ObservableCollection<PathPointViewModel>();
}
/// <summary>
/// 初始化默认值(用于新建路径)
/// </summary>
private void InitializeDefaultsForNewRoute()
{
_id = Guid.NewGuid().ToString();
_name = "新路径";
_description = "";
_isActive = false;
_createdTime = DateTime.Now;
_lastModifiedTime = DateTime.Now;
_isValidated = false;
_validationStatus = "未验证";
// 初始化点集合
Points = new ObservableCollection<PathPointViewModel>();
}
/// <summary>
/// 完成初始化
/// </summary>
private void CompleteInitialization()
{
try
{
// 订阅Points集合变更事件
if (Points != null)
{
Points.CollectionChanged += OnPointsCollectionChanged;
}
// 设置初始化完成标志
_isInitialized = true;
OnPropertyChanged(nameof(IsInitialized));
LogManager.Debug($"PathRouteViewModel初始化完成{_name}");
}
catch (Exception ex)
{
LogManager.Error($"PathRouteViewModel初始化异常: {ex.Message}", ex);
}
}
/// <summary>
/// 异步初始化方法(保留用于向后兼容)
/// </summary>
/// <returns>异步任务</returns>
[Obsolete("已改为同步初始化,此方法保留用于向后兼容")]
public async Task InitializeAsync()
{
await Task.CompletedTask; // 现在初始化已经在构造函数中同步完成
}
/// <summary>
/// 处理Points集合变更事件
/// </summary>
private void OnPointsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
SafeExecute(() =>
{
// 通知相关属性变更
OnPropertyChanged(nameof(PointCount));
OnPropertyChanged(nameof(SummaryInfo));
// TotalLength直接从Route读取不需要手动通知
// 更新最后修改时间
_lastModifiedTime = DateTime.Now;
OnPropertyChanged(nameof(LastModifiedTime));
// 标记为未验证
if (_isValidated)
{
_isValidated = false;
_validationStatus = "需要重新验证";
OnPropertyChanged(nameof(IsValidated));
OnPropertyChanged(nameof(ValidationStatus));
}
}, "处理Points集合变更");
}
#endregion
#region
/// <summary>
/// 异步添加路径点
/// </summary>
/// <param name="point">要添加的路径点</param>
/// <returns>异步任务</returns>
public async Task AddPointAsync(PathPointViewModel point)
{
if (point == null)
{
throw new ArgumentNullException(nameof(point));
}
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
Points.Add(point);
LogManager.Debug($"添加路径点:{point.Name} 到路径 {_name}");
});
}, "添加路径点");
}
/// <summary>
/// 异步批量添加路径点
/// </summary>
/// <param name="points">要添加的路径点集合</param>
/// <returns>异步任务</returns>
public async Task AddPointsAsync(IEnumerable<PathPointViewModel> points)
{
if (points == null)
{
throw new ArgumentNullException(nameof(points));
}
var pointList = points.ToList();
if (pointList.Count == 0)
{
return;
}
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
foreach (var point in pointList)
{
Points.Add(point);
}
LogManager.Debug($"批量添加{pointList.Count}个路径点到路径 {_name}");
});
}, "批量添加路径点");
}
/// <summary>
/// 异步移除路径点
/// </summary>
/// <param name="point">要移除的路径点</param>
/// <returns>是否成功移除</returns>
public async Task<bool> RemovePointAsync(PathPointViewModel point)
{
if (point == null)
{
return false;
}
try
{
return await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
bool removed = Points.Remove(point);
if (removed)
{
LogManager.Debug($"移除路径点:{point.Name} 从路径 {_name}");
}
return removed;
});
}
catch (Exception ex)
{
LogManager.Error($"移除路径点失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 异步清空所有路径点
/// </summary>
/// <returns>异步任务</returns>
public async Task ClearPointsAsync()
{
await SafeExecuteAsync(async () =>
{
await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
var count = Points.Count;
Points.Clear();
LogManager.Debug($"清空路径 {_name} 的所有路径点,共{count}个");
});
}, "清空路径点");
}
/// <summary>
/// 异步验证路径有效性
/// </summary>
/// <returns>验证结果</returns>
public async Task<bool> ValidateAsync()
{
try
{
// 先在UI线程上创建快照确保线程安全
var pointsSnapshot = await _uiStateManager.ExecuteUIUpdateAsync(() =>
{
return Points?.ToList() ?? new List<PathPointViewModel>();
});
var nameSnapshot = await _uiStateManager.ExecuteUIUpdateAsync(() => _name);
// 然后在后台线程验证
return await Task.Run(() =>
{
bool isValid = true;
var validationMessages = new List<string>();
// 检查路径点数量
if (pointsSnapshot.Count < 2)
{
isValid = false;
validationMessages.Add("路径至少需要2个点");
}
// 检查路径名称
if (string.IsNullOrWhiteSpace(nameSnapshot))
{
isValid = false;
validationMessages.Add("路径名称不能为空");
}
// 检查重复点
var duplicatePoints = pointsSnapshot
.GroupBy(p => new { p.X, p.Y, p.Z })
.Where(g => g.Count() > 1)
.ToList();
if (duplicatePoints.Any())
{
isValid = false;
validationMessages.Add($"发现{duplicatePoints.Count}组重复坐标的点");
}
// 在UI线程上更新验证状态
_uiStateManager.QueueUIUpdate(() =>
{
_isValidated = true;
_validationStatus = isValid ? "验证通过" : string.Join("; ", validationMessages);
OnPropertyChanged(nameof(IsValidated));
OnPropertyChanged(nameof(ValidationStatus));
});
LogManager.Debug($"路径验证完成:{nameSnapshot},结果:{(isValid ? "" : "")}");
return isValid;
});
}
catch (Exception ex)
{
LogManager.Error($"验证路径失败: {ex.Message}");
return false;
}
}
/// <summary>
/// 获取指定索引的路径点
/// </summary>
/// <param name="index">索引</param>
/// <returns>路径点如果索引无效返回null</returns>
public PathPointViewModel GetPointAt(int index)
{
return SafeExecute(() =>
{
if (index >= 0 && index < Points.Count)
{
return Points[index];
}
return null;
}, null, "获取指定索引路径点");
}
/// <summary>
/// 查找指定名称的路径点
/// </summary>
/// <param name="name">点名称</param>
/// <returns>匹配的路径点如果未找到返回null</returns>
public PathPointViewModel FindPoint(string name)
{
if (string.IsNullOrEmpty(name))
{
return null;
}
return SafeExecute(() =>
{
return Points.FirstOrDefault(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}, null, "查找路径点");
}
#endregion
#region
/// <summary>
/// 向后兼容:同步版本的添加点方法
/// </summary>
/// <param name="point">要添加的路径点</param>
[Obsolete("请使用AddPointAsync方法以获得更好的性能", false)]
public void AddPoint(PathPointViewModel point)
{
_ = AddPointAsync(point);
}
/// <summary>
/// 向后兼容:同步版本的移除点方法
/// </summary>
/// <param name="point">要移除的路径点</param>
/// <returns>是否成功移除</returns>
[Obsolete("请使用RemovePointAsync方法以获得更好的性能", false)]
public bool RemovePoint(PathPointViewModel point)
{
return RemovePointAsync(point).Result;
}
/// <summary>
/// 向后兼容:同步版本的清空方法
/// </summary>
[Obsolete("请使用ClearPointsAsync方法以获得更好的性能", false)]
public void ClearPoints()
{
_ = ClearPointsAsync();
}
/// <summary>
/// 向后兼容提供ObservableCollection接口
/// </summary>
[Obsolete("直接使用Points属性它已经是线程安全的ThreadSafeObservableCollection", false)]
public ObservableCollection<PathPointViewModel> GetPointsAsObservableCollection()
{
// 返回原始的ThreadSafeObservableCollection它继承自ObservableCollection
return Points;
}
/// <summary>
/// 验证ViewModel状态是否正常
/// </summary>
/// <returns>是否处于有效状态</returns>
public bool IsValidState()
{
return _uiStateManager != null &&
Points != null &&
_isInitialized;
}
/// <summary>
/// 获取ViewModel状态信息
/// </summary>
/// <returns>状态描述字符串</returns>
public string GetStateInfo()
{
return $"名称: {_name}, " +
$"点数量: {Points?.Count ?? 0}, " +
$"活动状态: {_isActive}, " +
$"已初始化: {_isInitialized}, " +
$"验证状态: {_validationStatus}";
}
#endregion
}
}