using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics.Tracing; using System.Linq; using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params; using Sicentury.Core; namespace MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel { /// /// 配方步骤集合。 /// /// /// 该集合继承自。 /// public sealed class RecipeStepCollection : ObservableCollection, IDisposable { #region Variables public event EventHandler OnSavedStateChanged; public event EventHandler HighlightStateChanged; public event EventHandler GasFlowCalculated; public event EventHandler StepTimeChanged; private bool _isLoadingRecipe; private bool? _isAllStepsSelected; private bool _isSaved; #endregion #region Constructors /// /// 创建配方步骤集合的实例。 /// public RecipeStepCollection() { _isSaved = true; } /// /// 创建配方步骤集合的实例。 /// /// /// 父级配方对象,请参考。 /// public RecipeStepCollection(RecipeData parent) : this() { Parent = parent; } /// /// 创建配方步骤集合的实例。 /// /// 配方步骤数组。 /// /// 父级配方对象,请参考。 /// public RecipeStepCollection(IList steps, RecipeData parent) : base(steps) { _isSaved = true; Parent = parent; foreach (var step in steps) step.Parent = parent; } #endregion #region Properties /// /// 返回父级配方对象的实例。 /// public RecipeData Parent { get; } /// /// 返回当前配方是否已经被保存。 /// public bool IsSaved { get => _isSaved; private set { _isSaved = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsSaved))); OnSavedStateChanged?.Invoke(this, _isSaved); } } public bool? IsAllStepsSelected { get { var groupSelection = this.GroupBy(x => x.IsSelected).ToList(); if (groupSelection.Count == 1) _isAllStepsSelected = groupSelection[0].Key; else _isAllStepsSelected = null; return _isAllStepsSelected; } set { if (!_isAllStepsSelected.HasValue || _isAllStepsSelected == true) DeselectAll(); else SelectAll(); OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsAllStepsSelected))); } } /// /// 返回被选中的配方步骤。 /// public IReadOnlyList SelectedSteps => this.ToList().Where(x => x.StepNoParam != null && x.StepNoParam.IsChecked).ToList(); #endregion #region Methods private void RegisterEvents(RecipeStep step) { step.SavedStateChanged += ItemOnSavedStateChanged; step.SelectionStateChanged += StepOnSelectionStateChanged; step.HighlightStateChanged += HighlightStateChanged; step.GasFlowCalculated += GasFlowCalculated; step.StepTimeChanged += StepTimeChanged; } public void UnRegisterEvents(RecipeStep step) { step.SavedStateChanged -= ItemOnSavedStateChanged; step.SelectionStateChanged -= StepOnSelectionStateChanged; step.HighlightStateChanged -= HighlightStateChanged; step.GasFlowCalculated -= GasFlowCalculated; step.StepTimeChanged -= StepTimeChanged; } /// /// 当配方中的某步骤的IsSaved状态发生变化时,触发此事件。 /// /// /// private void ItemOnSavedStateChanged(object sender, bool e) { if (e == false) IsSaved = false; else IsSaved = (this.ToList().FirstOrDefault(x => x.IsSaved == false) == null); } /// /// 当配方步骤的选中状态发生变化时,触发此事件。 /// /// /// private void StepOnSelectionStateChanged(object sender, bool e) { OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsAllStepsSelected))); } /// /// 更新Step序列号。 /// /// public void UpdateStepIndex(bool markAsSaved = false) { var step = this.FirstOrDefault(); var stepNo = step?.StepNoParam; if (stepNo == null) return; var index = RecipeFormatBuilder.STEP_INDEX_BASE; while (true) { stepNo.Value = index; if (markAsSaved) stepNo.Save(); //! 最后一个步骤的Next应该为Null,此时跳出循环。 if (stepNo.Next is StepParam nextParam) stepNo = nextParam; else break; index++; } } /// /// 开始加载Recipe。 /// public IDisposable BeginLoading() { _isLoadingRecipe = true; IsSaved = true; return this; } /// /// 结束加载Recipe /// public void EndLoading() { _isLoadingRecipe = false; IsSaved = true; } /// /// 计算所有步骤的总时长。 /// /// public double GetTotalTime() { return this.Sum(x => x.StepTime); } /// /// 选择当前集合中的所有配方步骤。 /// public void SelectAll() { foreach (var step in this) { step.IsSelected = true; } } /// /// 取消选择当前集合中的所有配方步骤。 /// public void DeselectAll() { foreach (var step in this) { step.IsSelected = false; } } /// /// 反向选择当前集合中的所有配方步骤。 /// public void ReverseSelection() { foreach (var step in this) { step.IsSelected = !step.IsSelected; } } /// /// 保存当前配方。 /// public void Save() { this.ToList().ForEach(x => x.Save()); } /// /// 取消所有参数的Highlight状态。 /// public void ResetHighlight() { this.ToList().ForEach(x => x.ResetHighlight()); } /// /// 校验所有步骤。 /// internal void Validate() { this.ToList().ForEach(step => { step.Validate(); }); } #endregion #region Overrided Methods /// /// /// /// /// private static void LinkSteps(RecipeStep previous, RecipeStep next) { if (previous != null && next != null) { previous.SetNextStep(next); next.SetPreviousStep(previous); } else if (previous == null && next != null) { next.SetPreviousStep(null); } else { previous?.SetNextStep(null); } } protected override void SetItem(int index, RecipeStep item) { throw new NotSupportedException(); } protected override void InsertItem(int index, RecipeStep step) { if (step != null) { // 如果Step没有分配Uid,先分配一个。 if (string.IsNullOrEmpty(step.StepUid)) { // 尝试20次,如果均重号,则报错。 var retry = 0; for (retry = 0; retry < 20; retry++) { var uid = GlobalDefs.GetShortUid(); if (this.FirstOrDefault(x => x.StepUid == uid) == null) { step.StepUid = uid; break; } } if (retry == 20) throw new Exception("unable to add recipe step since the exclusive UID can not be assigned."); } } base.InsertItem(index, step); if (step != null) { step.Parent = Parent; RegisterEvents(step); if (index > 0 && index < Count - 1) { LinkSteps(this[index - 1], this[index]); LinkSteps(this[index], this[index + 1]); } else if (index == 0) { if (Count > 1) { LinkSteps(null, this[index]); LinkSteps(this[index], this[index + 1]); } else { LinkSteps(null, this[index]); LinkSteps(this[index], null); } } else if (index == Count - 1) { LinkSteps(this[index - 1], this[index]); LinkSteps(this[index], null); } } // 如果不是加载Recipe状态,则为新增步骤,需要校验并更新保存状态 if (!_isLoadingRecipe) { UpdateStepIndex(); this[index].Validate(); // 强制标记为为保存状态 IsSaved = false; } } protected override void RemoveItem(int index) { if (Count > 0) { if (index >= 0 && index < Count) { UnRegisterEvents(this[index]); } } IsSaved = false; // 将前后两个Param链接起来 var preStep = this[index].Previous; var nextStep = this[index].Next; LinkSteps(preStep, nextStep); preStep?.Validate(); nextStep?.Validate(); base.RemoveItem(index); UpdateStepIndex(); // 强制标记为为保存状态 IsSaved = false; } protected override void ClearItems() { if (Count > 0) { this.ToList().ForEach(UnRegisterEvents); IsSaved = false; } else { IsSaved = true; } base.ClearItems(); // 强制标记为为保存状态 IsSaved = false; } protected override void MoveItem(int oldIndex, int newIndex) { throw new NotSupportedException(); } #endregion public void Dispose() { } } }