using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using MECF.Framework.Common.DataCenter; using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params; namespace MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel { public class RecipeStep : ObservableCollection { /// /// 步骤起始编号。 /// public const int START_INDEX = 1; #region Variables private bool _isHideValue; private bool _isProcessed; /// /// 当配方步骤的IsSaved属性发生变化时,触发此事件。 /// public event EventHandler SavedStateChanged; #endregion #region Constructors public RecipeStep(RecipeStep previous) { Previous = previous; IsSaved = true; } #endregion #region Properties /// /// 父级配方集合。 /// public RecipeData Parent { get; internal set; } /// /// 返回配方步骤序号参数。 /// public StepParam StepNoParam => this.FirstOrDefault(x => x is StepParam) as StepParam; public StringParam UidParam => this.FirstOrDefault(param => param.DisplayName == "Uid") as StringParam; /// /// 当前配方步骤的唯一识别码。 /// public string StepUid { get => UidParam?.Value ?? null; set { var paramUid = UidParam; if (paramUid != null) { paramUid.Value = value; } } } /// /// 返回步骤序号。 /// public int? StepNo { get { var param = StepNoParam; return param?.Value ?? null; } } /// /// 返回步骤执行时长。 /// public double StepTime { get { var param = FindParamByControlName(RecipeControlNames.STEP_TIME); if(param is DoubleParam dblParam) return dblParam.Value; return 0d; } } /// /// 返回当前配方步骤是否已保存。 /// public bool IsSaved { get; private set; } /// /// 返回当前步骤是否已经跑完工艺。 /// public bool IsProcessed { get => _isProcessed; set { if (_isProcessed != value) { _isProcessed = value; OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsProcessed))); } } } /// /// 返回前序配方。 /// public RecipeStep Previous { get; private set; } /// /// 返回后序配方。 /// public RecipeStep Next { get; private set; } /// /// 返回是否隐藏当前步骤的参数值。 /// public bool IsHideValue { get => _isHideValue; set { _isHideValue = value; this.ToList().ForEach(x => x.IsHideValue = value); } } #endregion #region Methods /// /// 当配方中的参数的属性发生变化时,触发此事件。 /// /// /// private void ParamOnPropertyChanged(object sender, PropertyChangedEventArgs e) { if (!(sender is IParam param)) return; if (e.PropertyName == nameof(Param.IsSaved)) { if (param.IsSaved == false) { IsSaved = false; } else { IsSaved = this.ToList().FirstOrDefault(x => x.IsSaved == false) == null; } SavedStateChanged?.Invoke(this, IsSaved); } } /// /// 将指定的Param链接到前序Param。 /// /// 当前Step中的参数。 private void LinkWithPreviousParam(IParam param) { var preParam = Previous?.FirstOrDefault(x => x.Name == param.Name); param.Previous = preParam; if (preParam != null) preParam.Next = param; } /// /// 将指定的Param链接到后序Param。 /// /// 当前Step中的参数。 private void LinkWithNextParam(IParam param) { var nextParam = Next?.FirstOrDefault(x => x.Name == param.Name); param.Next = nextParam; if (nextParam != null) nextParam.Previous = param; } /// /// 在当前步骤中查找指定控制名的参数。 /// /// /// 参数控制的名称。 /// /// /// 是否区分大小写。 /// /// public IParam FindParamByControlName(string controlName, bool isIgnoreCase = true) { return this.FirstOrDefault(x => string.Equals(x.Name, controlName, isIgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture)); } /// /// 校验步骤中的所有参数。 /// public void Validate() { this.ToList().ForEach(x => x.Validate()); } /// /// 取消所有参数的Highlight状态。 /// public void ResetHighlight() { this.ToList().ForEach(x => x.ResetHighlight()); } /// /// 获取高亮显示的参数。 /// /// public List GetHighlightedParams() { return this.ToList().Where(p => p.IsHighlighted).ToList(); } /// /// 保存当前配方步骤。 /// public void Save() { this.ToList().ForEach(x => x.Save()); } /// /// 設置前序步驟。 /// /// public void SetPreviousStep(RecipeStep step) { Previous = step; // 调整Step中Param的链接关系 this.ToList().ForEach(LinkWithPreviousParam); if (Previous == null) return; // 将前序步骤的后序步骤链接到我自己。 Previous.Next = this; } public void SetNextStep(RecipeStep step) { Next = step; this.ToList().ForEach(LinkWithNextParam); } /// /// 检查StepNo是否为有效值。 /// /// /// /// public static bool ValidateStepNo(int? stepNo, out int validatedStepNo) { validatedStepNo = int.MinValue; var isValid = stepNo >= START_INDEX; if (isValid) validatedStepNo = stepNo.Value; return isValid; } #endregion #region Override Methods protected override void InsertItem(int index, Param item) { if (item != null) { item.Parent = this; LinkWithPreviousParam(item); LinkWithNextParam(item); item.PropertyChanged += ParamOnPropertyChanged; } base.InsertItem(index, item); } protected override void SetItem(int index, Param item) { throw new NotSupportedException(); } protected override void RemoveItem(int index) { if (Count > 0) { if (index >= 0 && index < Count) { this[index].PropertyChanged -= ParamOnPropertyChanged; } } // 将前后两个Param链接起来 var preParam = this[index].Previous; var nextParam = this[index].Next; if (preParam != null && nextParam != null) { preParam.Next = nextParam; nextParam.Previous = preParam; } else if (preParam == null && nextParam != null) { nextParam.Previous = null; } else if (preParam != null) { preParam.Next = null; } IsSaved = false; SavedStateChanged?.Invoke(this, true); base.RemoveItem(index); } protected override void ClearItems() { this.ToList().ForEach(x => x.PropertyChanged -= ParamOnPropertyChanged); IsSaved = Count <= 0; SavedStateChanged?.Invoke(this, true); base.ClearItems(); } public override string ToString() { return Count > 0 ? (StepNoParam == null ? "Recipe Step, Item={Count}" : StepNoParam.ToString()) : "Empty Recipe Step"; } #endregion } }