Sic.Framework/MECF.Framework.UI.Client/RecipeEditorLib/RecipeModel/RecipeStepCollection.cs

420 lines
12 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.RecipeEditorLib.RecipeModel.Params;
using Sicentury.Core;
namespace MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel
{
/// <summary>
/// 配方步骤集合。
/// </summary>
/// <remarks>
/// 该集合继承自<see cref="ObservableCollection{T}"/>。
/// </remarks>
public sealed class RecipeStepCollection : ObservableCollection<RecipeStep>, IDisposable
{
#region Variables
public event EventHandler<bool> OnSavedStateChanged;
public event EventHandler HighlightStateChanged;
public event EventHandler GasFlowCalculated;
private bool _isLoadingRecipe;
private bool? _isAllStepsSelected;
private bool _isSaved;
#endregion
#region Constructors
/// <summary>
/// 创建配方步骤集合的实例。
/// </summary>
public RecipeStepCollection()
{
_isSaved = true;
}
/// <summary>
/// 创建配方步骤集合的实例。
/// </summary>
/// <param name="parent">
/// 父级配方对象,请参考<see cref="RecipeData"/>。
/// </param>
public RecipeStepCollection(RecipeData parent) : this()
{
Parent = parent;
}
/// <summary>
/// 创建配方步骤集合的实例。
/// </summary>
/// <param name="steps">配方步骤数组。</param>
/// <param name="parent">
/// 父级配方对象,请参考<see cref="RecipeData"/>。
/// </param>
public RecipeStepCollection(IList<RecipeStep> steps, RecipeData parent)
: base(steps)
{
_isSaved = true;
Parent = parent;
foreach (var step in steps)
step.Parent = parent;
}
#endregion
#region Properties
/// <summary>
/// 返回父级配方对象的实例。
/// </summary>
public RecipeData Parent { get; }
/// <summary>
/// 返回当前配方是否已经被保存。
/// </summary>
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)));
}
}
/// <summary>
/// 返回被选中的配方步骤。
/// </summary>
public IReadOnlyList<RecipeStep> SelectedSteps =>
this.ToList().Where(x => x.StepNoParam != null && x.StepNoParam.IsChecked).ToList();
#endregion
#region Methods
/// <summary>
/// 当配方中的某步骤的IsSaved状态发生变化时触发此事件。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ItemOnSavedStateChanged(object sender, bool e)
{
if (e == false)
IsSaved = false;
else
IsSaved = (this.ToList().FirstOrDefault(x => x.IsSaved == false) == null);
}
/// <summary>
/// 当配方步骤的选中状态发生变化时,触发此事件。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StepOnSelectionStateChanged(object sender, bool e)
{
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsAllStepsSelected)));
}
/// <summary>
/// 更新Step序列号。
/// </summary>
/// <param name="markAsSaved"></param>
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++;
}
}
/// <summary>
/// 开始加载Recipe。
/// </summary>
public IDisposable BeginLoading()
{
_isLoadingRecipe = true;
IsSaved = true;
return this;
}
/// <summary>
/// 结束加载Recipe
/// </summary>
public void EndLoading()
{
this.ToList().ForEach(step =>
{
step.Validate();
});
_isLoadingRecipe = false;
IsSaved = true;
}
/// <summary>
/// 选择当前集合中的所有配方步骤。
/// </summary>
public void SelectAll()
{
foreach (var step in this)
{
step.IsSelected = true;
}
}
/// <summary>
/// 取消选择当前集合中的所有配方步骤。
/// </summary>
public void DeselectAll()
{
foreach (var step in this)
{
step.IsSelected = false;
}
}
/// <summary>
/// 反向选择当前集合中的所有配方步骤。
/// </summary>
public void ReverseSelection()
{
foreach (var step in this)
{
step.IsSelected = !step.IsSelected;
}
}
/// <summary>
/// 保存当前配方。
/// </summary>
public void Save()
{
this.ToList().ForEach(x => x.Save());
}
/// <summary>
/// 取消所有参数的Highlight状态。
/// </summary>
public void ResetHighlight()
{
this.ToList().ForEach(x => x.ResetHighlight());
}
#endregion
#region Overrided Methods
/// <summary>
///
/// </summary>
/// <param name="previous"></param>
/// <param name="next"></param>
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;
step.SavedStateChanged += ItemOnSavedStateChanged;
step.SelectionStateChanged += StepOnSelectionStateChanged;
step.HighlightStateChanged += HighlightStateChanged;
step.GasFlowCalculated += GasFlowCalculated;
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)
{
this[index].SavedStateChanged -= ItemOnSavedStateChanged;
this[index].SelectionStateChanged -= StepOnSelectionStateChanged;
this[index].HighlightStateChanged -= HighlightStateChanged;
this[index].GasFlowCalculated -= GasFlowCalculated;
}
}
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(x =>
{
x.SavedStateChanged -= ItemOnSavedStateChanged;
x.SelectionStateChanged -= StepOnSelectionStateChanged;
x.HighlightStateChanged -= HighlightStateChanged;
x.GasFlowCalculated -= GasFlowCalculated;
});
IsSaved = false;
}
else
{
IsSaved = true;
}
base.ClearItems();
// 强制标记为为保存状态
IsSaved = false;
}
protected override void MoveItem(int oldIndex, int newIndex)
{
throw new NotSupportedException();
}
#endregion
public void Dispose()
{
}
}
}