Sic.Framework-Nanjing-Baishi/MECF.Framework.UI.Client/RecipeEditorLib/RecipeModel/RecipeStep.cs

475 lines
14 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.ComponentModel;
using System.Linq;
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
using MECF.Framework.UI.Client.CenterViews.Editors;
using MECF.Framework.UI.Client.ClientBase;
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
namespace MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel
{
public class RecipeStep : ObservableCollection<Param>
{
#region Variables
private MenuPermissionEnum _permission;
private bool _isHideValue;
private bool _isProcessed;
private bool _isVisible;
/// <summary>
/// 当步骤的任意参数的<see cref="Param.IsSaved"/>属性发生变化时,引发此事件。
/// </summary>
public event EventHandler<bool> SavedStateChanged;
/// <summary>
/// 当前步骤的选择状态发生变化时,引发此事件。
/// </summary>
public event EventHandler<bool> SelectionStateChanged;
/// <summary>
/// 当前步骤的任意参数高亮状态发生变化时,引发此事件。
/// </summary>
public event EventHandler HighlightStateChanged;
/// <summary>
/// 当前步骤的气体流量计算完成后,引发此事件。
/// </summary>
public event EventHandler GasFlowCalculated;
/// <summary>
/// 当步骤的时长发生变化时,引发此事件。
/// </summary>
public event EventHandler StepTimeChanged;
#endregion
#region Constructors
public RecipeStep(RecipeStep previous)
{
Previous = previous;
IsSaved = true;
IsVisible = true;
}
#endregion
#region Properties
/// <summary>
/// 设置或返回当前步骤的访问权限。
/// </summary>
public MenuPermissionEnum Permission
{
get => _permission;
set
{
_permission = value;
this.ToList().ForEach(x => x.StepPermission = _permission);
}
}
/// <summary>
/// 父级配方集合。
/// </summary>
public RecipeData Parent { get; internal set; }
/// <summary>
/// 返回配方步骤序号参数。
/// </summary>
public StepParam StepNoParam => this.FirstOrDefault(param => param.Name == RecipeFormatBuilder.SPEC_COL_STEPNO) as StepParam;
private StringParam UidParam => this.FirstOrDefault(param => param.Name == RecipeFormatBuilder.SPEC_COL_STEPUID) as StringParam;
/// <summary>
/// 返回当前步骤是否被选中。
/// </summary>
public bool IsSelected
{
get => StepNoParam?.IsChecked ?? false;
set
{
if (StepNoParam != null)
StepNoParam.IsChecked = value;
}
}
/// <summary>
/// 当前配方步骤的唯一识别码。
/// </summary>
public string StepUid
{
get => UidParam?.Value ?? null;
set
{
var paramUid = UidParam;
if (paramUid != null)
{
paramUid.Value = value;
}
}
}
/// <summary>
/// 返回步骤序号。
/// </summary>
public int? StepNo => StepNoParam?.Value;
/// <summary>
/// 返回步骤执行时长。
/// </summary>
public double StepTime
{
get
{
var param = FindParamByControlName(RecipeControlNames.STEP_TIME);
if(param is DoubleParam dblParam)
return dblParam.Value;
return 0d;
}
}
/// <summary>
/// 返回当前配方步骤是否已保存。
/// </summary>
public bool IsSaved { get; private set; }
/// <summary>
/// 返回当前步骤是否已经跑完工艺。
/// </summary>
public bool IsProcessed
{
get => _isProcessed;
set
{
if (_isProcessed != value)
{
_isProcessed = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsProcessed)));
}
}
}
/// <summary>
/// 返回前序配方。
/// </summary>
public RecipeStep Previous { get; private set; }
/// <summary>
/// 返回后序配方。
/// </summary>
public RecipeStep Next { get; private set; }
/// <summary>
/// 设置或返回当前步骤是否在DataGrid中显示。
/// </summary>
public bool IsVisible
{
get => _isVisible;
set
{
_isVisible = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsVisible)));
}
}
#endregion
#region Methods
/// <summary>
/// 当配方中的参数的属性发生变化时,触发此事件。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnParamPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (sender is not IParam param)
return;
switch (e.PropertyName)
{
case nameof(Param.IsSaved):
{
if (param.IsSaved == false)
IsSaved = false;
else
IsSaved = this.ToList().FirstOrDefault(x => x.IsSaved == false) == null;
SavedStateChanged?.Invoke(this, IsSaved);
break;
}
case nameof(StepParam.IsChecked):
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsSelected)));
SelectionStateChanged?.Invoke(this, IsSelected);
break;
case nameof(Param.IsHighlighted):
HighlightStateChanged?.Invoke(this, EventArgs.Empty);
break;
}
}
/// <summary>
/// 当配方中的参数的值发生变化时,触发此事件。
/// </summary>
/// <remarks>
/// 该事件在DragToFill操作时会被触发。
/// 单元格编辑完成后参数值发生变化不会引发此事件而是直接在CellEndEditing事件中处理。
/// </remarks>
/// <param name="sender"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private void OnParamValueChanged(object sender, object e)
{
if (sender is Param para and IValueParam )
{
if (para.Name == RecipeControlNames.STEP_TIME)
{
StepTimeChanged?.Invoke(this, EventArgs.Empty);
}
else
{
//TODO 和气体不相关的参数修改后,不应该触发气体流量计算过程
CalculateGasFlow();
}
}
}
/// <summary>
/// 将指定的Param链接到前序Param。
/// </summary>
/// <param name="param">当前Step中的参数。</param>
private void LinkWithPreviousParam(IParam param)
{
var preParam = Previous?.FirstOrDefault(x => x.Name == param.Name);
param.Previous = preParam;
if (preParam != null)
preParam.Next = param;
}
/// <summary>
/// 将指定的Param链接到后序Param。
/// </summary>
/// <param name="param">当前Step中的参数。</param>
private void LinkWithNextParam(IParam param)
{
var nextParam = Next?.FirstOrDefault(x => x.Name == param.Name);
param.Next = nextParam;
if (nextParam != null)
nextParam.Previous = param;
}
/// <summary>
/// 从角色配置中加载当前步骤的访问权限。
/// </summary>
/// <param name="role"></param>
internal void LoadPermission(PermissionHelper mp)
{
var mpKey = $"Step{StepNo}";
if (mp.MenuPermissionDictionary.TryGetValue(mpKey, out var stepPerm))
Permission = stepPerm;
else
Permission = MenuPermissionEnum.MP_NONE;
}
/// <summary>
/// 在当前步骤中查找指定控制名的参数。
/// </summary>
/// <param name="controlName">
/// 参数控制的名称。
/// </param>
/// <param name="isIgnoreCase">
/// 是否区分大小写。
/// </param>
/// <returns></returns>
public IParam FindParamByControlName(string controlName, bool isIgnoreCase = true)
{
return this.FirstOrDefault(x =>
string.Equals(x.Name, controlName,
isIgnoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture));
}
/// <summary>
/// 校验步骤中的所有参数。
/// </summary>
public void Validate()
{
this.ToList().ForEach(x => x.Validate());
}
/// <summary>
/// 计算当前步骤的气体流量。
/// </summary>
public void CalculateGasFlow()
{
if (Parent.RecipeType != RecipeType.Process)
return;
Parent?.CalculateGasFlow(this);
GasFlowCalculated?.Invoke(this, EventArgs.Empty);
}
/// <summary>
/// 取消所有参数的Highlight状态。
/// </summary>
public void ResetHighlight()
{
this.ToList().ForEach(x => x.ResetHighlight());
}
/// <summary>
/// 获取高亮显示的参数。
/// </summary>
/// <returns></returns>
public List<Param> GetHighlightedParams()
{
return this.ToList().Where(p => p.IsHighlighted).ToList();
}
/// <summary>
/// 保存当前配方步骤。
/// </summary>
public void Save()
{
this.ToList().ForEach(x => x.Save());
}
/// <summary>
/// 設置前序步驟。
/// </summary>
/// <param name="step"></param>
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);
}
/// <summary>
/// 检查StepNo是否为有效值。
/// </summary>
/// <param name="stepNo"></param>
/// <param name="validatedStepNo"></param>
/// <returns></returns>
public static bool ValidateStepNo(int? stepNo, out int validatedStepNo)
{
validatedStepNo = int.MinValue;
var isValid = stepNo >= RecipeFormatBuilder.STEP_INDEX_BASE;
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 += OnParamPropertyChanged;
if(item is IValueParam vp)
vp.OnValueChanged += OnParamValueChanged;
}
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 -= OnParamPropertyChanged;
if(this[index] is IValueParam vp)
vp.OnValueChanged -= OnParamValueChanged;
}
}
// 将前后两个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 -= OnParamPropertyChanged;
if(x is IValueParam vp)
vp.OnValueChanged -= OnParamValueChanged;
});
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
}
}