1966 lines
66 KiB
C#
1966 lines
66 KiB
C#
using Aitex.Core.RT.Log;
|
||
using Caliburn.Micro;
|
||
using Caliburn.Micro.Core;
|
||
using MECF.Framework.Common.CommonData;
|
||
using MECF.Framework.Common.DataCenter;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors.Recipe;
|
||
using MECF.Framework.UI.Client.CenterViews.Editors.Sequence;
|
||
using MECF.Framework.UI.Client.ClientBase;
|
||
using OpenSEMI.ClientBase;
|
||
using OpenSEMI.ClientBase.Command;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Collections.ObjectModel;
|
||
using System.ComponentModel;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using System.Windows;
|
||
using System.Windows.Controls;
|
||
using System.Windows.Data;
|
||
using System.Windows.Input;
|
||
using System.Windows.Media;
|
||
using System.Windows.Threading;
|
||
using MECF.Framework.UI.Client.CenterViews.Configs.Roles;
|
||
using MECF.Framework.UI.Client.CenterViews.Core;
|
||
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension;
|
||
using MECF.Framework.UI.Client.RecipeEditorLib.DGExtension.CustomColumn;
|
||
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel;
|
||
using MECF.Framework.UI.Client.RecipeEditorLib.RecipeModel.Params;
|
||
using Sicentury.Core;
|
||
using Action = System.Action;
|
||
using DataGridCellEditEndingEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridCellEditEndingEventArgs;
|
||
using DataGridRowEventArgs = ExtendedGrid.Microsoft.Windows.Controls.DataGridRowEventArgs;
|
||
using Sicentury.Core.Collections;
|
||
|
||
namespace SicUI.Models.RecipeEditors
|
||
{
|
||
public class ChamberTypeItem : NotifiableItem
|
||
{
|
||
public string ChamberType { get; set; }
|
||
public ObservableCollection<ProcessTypeFileItem> FileListByChamberType { get; set; }
|
||
|
||
public ChamberTypeItem()
|
||
{
|
||
FileListByChamberType = new ObservableCollection<ProcessTypeFileItem>();
|
||
}
|
||
}
|
||
|
||
public class RecipeEditorViewModel : UiViewModelBase, IHandle<UserMode> //BaseModel
|
||
{
|
||
|
||
#region Variables
|
||
|
||
private readonly IRecipeGasFlowCalculator _gasFlowCalculator;
|
||
private RecipeData _currentRecipe;
|
||
private bool _isRunPurgeSwitch;
|
||
private bool _isTmaNotInstall;
|
||
private bool _isHClNotInstall;
|
||
private bool _isHClFlowNotInstall;
|
||
private bool _isLoading;
|
||
private Window _winValidationInfo;
|
||
private EditMode _editMode;
|
||
private int _errorsCount;
|
||
private readonly RecipeFormatBuilder _columnBuilder;
|
||
private readonly RecipeProvider _recipeProvider;
|
||
private ObservableCollection<ProcessTypeFileItem> _processTypeFileList;
|
||
private readonly ObservableRangeCollection<RecipeStepValidationInfo> _validationResultList;
|
||
private Point? _lastPosOfValidationWin = null;
|
||
|
||
#endregion
|
||
|
||
#region Constructors
|
||
|
||
public RecipeEditorViewModel()
|
||
{
|
||
var eventAggregator = IoC.Get<IEventAggregator>();
|
||
eventAggregator?.Subscribe(this);
|
||
|
||
_gasFlowCalculator = IoC.Get<IRecipeGasFlowCalculator>();
|
||
_columnBuilder = new RecipeFormatBuilder();
|
||
_recipeProvider = new RecipeProvider();
|
||
_validationResultList = new ObservableRangeCollection<RecipeStepValidationInfo>();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Commands
|
||
|
||
private ICommand _RenameFolderCommand;
|
||
|
||
public ICommand RenameFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (_RenameFolderCommand == null)
|
||
_RenameFolderCommand = new BaseCommand(() => RenameFolder());
|
||
return _RenameFolderCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _DeleteFolderCommand;
|
||
|
||
public ICommand DeleteFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (_DeleteFolderCommand == null)
|
||
_DeleteFolderCommand = new BaseCommand(() => DeleteFolder());
|
||
return _DeleteFolderCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewFolderCommand;
|
||
|
||
public ICommand NewFolderCommand
|
||
{
|
||
get
|
||
{
|
||
if (_NewFolderCommand == null)
|
||
_NewFolderCommand = new BaseCommand(() => NewFolder());
|
||
return _NewFolderCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewFolderRootCommand;
|
||
|
||
public ICommand NewFolderRootCommand
|
||
{
|
||
get
|
||
{
|
||
if (_NewFolderRootCommand == null)
|
||
_NewFolderRootCommand = new BaseCommand(() => NewFolderRoot());
|
||
return _NewFolderRootCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewRecipeCommand;
|
||
|
||
public ICommand NewRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (_NewRecipeCommand == null)
|
||
_NewRecipeCommand = new BaseCommand(() => NewRecipe());
|
||
return _NewRecipeCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _NewRecipeRootCommand;
|
||
|
||
public ICommand NewRecipeRootCommand
|
||
{
|
||
get
|
||
{
|
||
if (_NewRecipeRootCommand == null)
|
||
_NewRecipeRootCommand = new BaseCommand(() => NewRecipeRoot());
|
||
return _NewRecipeRootCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _RenameRecipeCommand;
|
||
|
||
public ICommand RenameRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (_RenameRecipeCommand == null)
|
||
_RenameRecipeCommand = new BaseCommand(() => RenameRecipe());
|
||
return _RenameRecipeCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _DeleteRecipeCommand;
|
||
|
||
public ICommand DeleteRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (_DeleteRecipeCommand == null)
|
||
_DeleteRecipeCommand = new BaseCommand(() => DeleteRecipe());
|
||
return _DeleteRecipeCommand;
|
||
}
|
||
}
|
||
|
||
private ICommand _SaveAsRecipeCommand;
|
||
|
||
public ICommand SaveAsRecipeCommand
|
||
{
|
||
get
|
||
{
|
||
if (_SaveAsRecipeCommand == null)
|
||
_SaveAsRecipeCommand = new BaseCommand(() => SaveAsRecipe());
|
||
return _SaveAsRecipeCommand;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Properties
|
||
|
||
public ObservableCollection<ProcessTypeFileItem> ProcessTypeFileList
|
||
{
|
||
get => _processTypeFileList;
|
||
set
|
||
{
|
||
_processTypeFileList = value;
|
||
NotifyOfPropertyChange(nameof(ProcessTypeFileList));
|
||
}
|
||
}
|
||
|
||
public RecipeData CurrentRecipe
|
||
{
|
||
get => _currentRecipe;
|
||
set
|
||
{
|
||
_currentRecipe = value;
|
||
NotifyOfPropertyChange(nameof(CurrentRecipe));
|
||
}
|
||
}
|
||
|
||
public bool IsPermission => Permission == 3; //&& RtStatus != "AutoRunning";
|
||
|
||
public FileNode CurrentFileNode { get; set; }
|
||
|
||
private bool IsChanged => _editMode == EditMode.Edit || CurrentRecipe.IsChanged;
|
||
|
||
public List<EditorDataGridTemplateColumnBase> Columns { get; set; }
|
||
|
||
public Dictionary<string, List<EditorDataGridTemplateColumnBase>> DicColunms { get; set; }
|
||
|
||
public bool EnableNew { get; set; }
|
||
|
||
public bool EnableReName { get; set; }
|
||
|
||
public bool EnableCopy { get; set; }
|
||
|
||
public bool EnableDelete { get; set; }
|
||
|
||
public bool EnableSave { get; set; }
|
||
|
||
public bool EnableStep { get; set; }
|
||
|
||
public bool EnableReload { get; set; }
|
||
|
||
public bool EnableSaveToAll { get; set; }
|
||
|
||
public bool EnableSaveTo { get; set; }
|
||
|
||
public int ErrorsCount
|
||
{
|
||
set
|
||
{
|
||
// 如果错误数没发生变化,不要修改Badge的值,以免触发Badge动画。
|
||
if (value == _errorsCount)
|
||
return;
|
||
|
||
if(value == 0)
|
||
((RecipeEditorView)View).txtErrorCount.Badge = null;
|
||
else
|
||
((RecipeEditorView)View).txtErrorCount.Badge = value;
|
||
|
||
_errorsCount = value;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否正在加载配方。
|
||
/// </summary>
|
||
public bool IsLoading
|
||
{
|
||
get => _isLoading;
|
||
private set
|
||
{
|
||
_isLoading = value;
|
||
NotifyOfPropertyChange(nameof(IsLoading));
|
||
}
|
||
}
|
||
|
||
public RecipeStepCollection SelectedRecipeSteps { get; set; }
|
||
|
||
public ICollectionView ParamValidationInfoCollection =>
|
||
CollectionViewSource.GetDefaultView(_validationResultList);
|
||
|
||
public ObservableCollection<string> ChamberType { get; set; }
|
||
|
||
public int ChamberTypeIndexSelection { get; set; }
|
||
|
||
public int ProcessTypeIndexSelection { get; set; }
|
||
|
||
public string CurrentChamberType => ChamberType[ChamberTypeIndexSelection];
|
||
|
||
public string CurrentProcessType => ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
|
||
public Visibility MultiChamberVisibility { get; set; }
|
||
|
||
public ObservableCollection<string> Chambers { get; set; }
|
||
|
||
public string SelectedChamber { get; set; }
|
||
|
||
public object View { get; set; }
|
||
|
||
|
||
#endregion
|
||
|
||
protected override void OnInitialize()
|
||
{
|
||
base.OnInitialize();
|
||
|
||
var chamberType = QueryDataClient.Instance.Service.GetConfig("System.Recipe.SupportedChamberType");
|
||
if (chamberType == null)
|
||
{
|
||
ChamberType = new ObservableCollection<string>() { "Default" };
|
||
}
|
||
else
|
||
{
|
||
ChamberType = new ObservableCollection<string>(((string)(chamberType)).Split(','));
|
||
}
|
||
|
||
ChamberTypeIndexSelection = 0;
|
||
|
||
var processType = "Process,Routine,Clean";
|
||
|
||
ProcessTypeFileList = new ObservableCollection<ProcessTypeFileItem>();
|
||
var recipeProcessType = ((string)processType).Split(',');
|
||
|
||
for (var i = 0; i < recipeProcessType.Length; i++)
|
||
{
|
||
var type = new ProcessTypeFileItem();
|
||
type.ProcessType = recipeProcessType[i];
|
||
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{recipeProcessType[i]}";
|
||
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
||
type.FileListByProcessType =
|
||
RecipeSequenceTreeBuilder.BuildFileNode(prefix, "", false, recipes)[0].Files;
|
||
type.FilterFileListByProcessType = type.FileListByProcessType;
|
||
ProcessTypeFileList.Add(type);
|
||
}
|
||
|
||
DicColunms = new Dictionary<string, List<EditorDataGridTemplateColumnBase>>();
|
||
UpdateRecipeFormat();
|
||
}
|
||
|
||
protected override void OnActivate()
|
||
{
|
||
|
||
//初始化RoleManager
|
||
var roleManager = new RoleManager();
|
||
roleManager.Initialize();
|
||
|
||
//得到当前登录的RoleItem
|
||
var roleItem = roleManager.GetRoleByName(BaseApp.Instance.UserContext.RoleName);
|
||
var menuPermission = new MenuPermission();
|
||
menuPermission.ParsePermission(roleItem.Role.MenuPermission);
|
||
|
||
foreach (var col in Columns)
|
||
{
|
||
if (col.ControlName == "StepNo")
|
||
continue;
|
||
|
||
RecipeFormatBuilder.SetPermission(col, menuPermission);
|
||
}
|
||
|
||
//this.Columns = this._columnBuilder.Build($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, true, ClientApp.Instance.UserContext.RoleName);
|
||
|
||
base.OnActivate();
|
||
}
|
||
|
||
protected override void OnDeactivate(bool close)
|
||
{
|
||
base.OnDeactivate(close);
|
||
|
||
if (IsChanged)
|
||
{
|
||
if (DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
||
$"Recipe {CurrentRecipe.Name} content is changed, do you want to save it?") == DialogButton.Yes)
|
||
{
|
||
SaveRecipe();
|
||
}
|
||
}
|
||
|
||
_winValidationInfo?.Close();
|
||
|
||
// 锁定编辑器
|
||
((RecipeEditorView)View).editorLocker.Lock();
|
||
}
|
||
|
||
protected override void OnViewLoaded(object view)
|
||
{
|
||
View = view;
|
||
base.OnViewLoaded(view);
|
||
RecipeFormatBuilder.ApplyTemplate((UserControl)view, Columns);
|
||
var u = (RecipeEditorView)view;
|
||
u.dgCustom.Columns.Clear();
|
||
|
||
Columns.Apply((c) =>
|
||
{
|
||
c.Header = c;
|
||
u.dgCustom.Columns.Add(c);
|
||
|
||
});
|
||
|
||
u.dgCustom.ItemsSource = CurrentRecipe.Steps;
|
||
u.dgCustom.LostFocus += DgCustom_LostFocus;
|
||
u.dgCustom.CellEditEnding += DgCustomOnCellEditEnding;
|
||
u.dgCustom.LoadingRow += DgCustomOnLoadingRow;
|
||
u.dgCustom.FrozenColumnCount = 4;
|
||
}
|
||
|
||
private void DgCustomOnLoadingRow(object sender, DataGridRowEventArgs e)
|
||
{
|
||
if (sender is XDataGrid dg && e.Row.DataContext is RecipeStep step)
|
||
{
|
||
for (var i = 0; i < step.Count; i++)
|
||
{
|
||
step[i].RowOwner = e.Row;
|
||
step[i].ColumnOwner = dg.Columns[i];
|
||
}
|
||
}
|
||
}
|
||
|
||
private void DgCustomOnCellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
|
||
{
|
||
// ValidateEntireRecipe();
|
||
if (SelectedRecipeSteps != null && SelectedRecipeSteps.Count == 1)
|
||
{
|
||
SelectedRecipeSteps[0].CalculateGasFlow();
|
||
CheckIfAllCellsValid(out _);
|
||
}
|
||
}
|
||
|
||
private void DgCustom_LostFocus(object sender, RoutedEventArgs e)
|
||
{
|
||
// ValidateEntireRecipe();
|
||
if (SelectedRecipeSteps != null && SelectedRecipeSteps.Count == 1)
|
||
{
|
||
SelectedRecipeSteps[0].CalculateGasFlow();
|
||
CheckIfAllCellsValid(out _);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 校验整个Recipe。
|
||
/// </summary>
|
||
private void ValidateEntireRecipe()
|
||
{
|
||
_isRunPurgeSwitch = false;
|
||
_isTmaNotInstall = false;
|
||
_isHClNotInstall = false;
|
||
_isHClFlowNotInstall = false;
|
||
|
||
CurrentRecipe.RecipeTotalTime = 0;
|
||
|
||
for (var selectIndex = 0; selectIndex < CurrentRecipe.Steps.Count; selectIndex++)
|
||
{
|
||
var previousIndex = selectIndex == 0 ? 0 : selectIndex - 1;
|
||
var currentIndex = selectIndex;
|
||
var nextIndex = selectIndex == CurrentRecipe.Steps.Count - 1 ? selectIndex : selectIndex + 1;
|
||
|
||
var previousStep = CurrentRecipe.Steps[previousIndex];
|
||
var currentStep = CurrentRecipe.Steps[currentIndex];
|
||
var nextStep = CurrentRecipe.Steps[nextIndex];
|
||
|
||
//判断每步与上一步值是否相同,不同则以颜色区分
|
||
RenderStepsWithSameValue(previousStep, currentStep);
|
||
|
||
//如果是Routine则在下面代码不执行,在这里continue
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
//如果是Routine,则总时间需*循环次数
|
||
var loopTimes = ((DoubleParam)currentStep[8]).Value <= 0
|
||
? 1
|
||
: (int)((DoubleParam)currentStep[8]).Value;
|
||
CurrentRecipe.RecipeTotalTime += (int)currentStep.StepTime * loopTimes;
|
||
|
||
continue;
|
||
}
|
||
else
|
||
{
|
||
//如果是Recipe则总时间直接加
|
||
CurrentRecipe.RecipeTotalTime += (int)currentStep.StepTime;
|
||
}
|
||
|
||
|
||
NotInstallDevice(currentStep);
|
||
currentStep.CalculateGasFlow(); // 自动计算比例值
|
||
currentStep.Validate(); // 校验单元格
|
||
}
|
||
|
||
//如果是Routine则在下面代码不执行,在这里返回
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (_isRunPurgeSwitch)
|
||
MessageBox.Show("Flow mode 'Run' and 'Purge' can't switch directly", "Warning", MessageBoxButton.OK,
|
||
MessageBoxImage.Warning);
|
||
|
||
//if (_isTmaNotInstall)
|
||
// MessageBox.Show("TMA is not install, only Purge mode is valid", "Warning", MessageBoxButton.OK,
|
||
// MessageBoxImage.Warning);
|
||
|
||
if (_isHClNotInstall)
|
||
MessageBox.Show("GR Purge HCl is not install, only Disable is valid", "Warning", MessageBoxButton.OK,
|
||
MessageBoxImage.Warning);
|
||
|
||
if (_isHClFlowNotInstall)
|
||
MessageBox.Show("GR Purge HCl Flow is not install, lock the value as zero", "Warning",
|
||
MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
}
|
||
|
||
private static void RenderStepsWithSameValue(IReadOnlyList<Param> previousStep, IReadOnlyList<Param> currentStep)
|
||
{
|
||
for (var i = 0; i < currentStep.Count; i++)
|
||
{
|
||
if (currentStep[i] is DoubleParam dblParamCurr && previousStep[i] is DoubleParam dblParamPrev)
|
||
{
|
||
dblParamCurr.IsEqualsToPrevious =
|
||
GlobalDefs.IsDoubleValueEquals(dblParamCurr.Value, dblParamPrev.Value);
|
||
}
|
||
|
||
else if (currentStep[i] is ComboxParam cbxParamCurr && previousStep[i] is ComboxParam cbxParamPrev)
|
||
{
|
||
if (cbxParamCurr.Value != cbxParamPrev.Value)
|
||
{
|
||
cbxParamCurr.IsEqualsToPrevious = false;
|
||
}
|
||
else
|
||
{
|
||
cbxParamCurr.IsEqualsToPrevious = true;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
private void NotInstallDevice(RecipeStep currentStep)
|
||
{
|
||
if (!(currentStep.FindParamByControlName("TMA.SetValve") is ComboxParam currentTmaFlowMode))
|
||
throw new InvalidOperationException(
|
||
$"the param TMA.SetValve is not TMA Flow Mode, please check the recipe format file.");
|
||
|
||
if (string.Equals(currentTmaFlowMode.Value,
|
||
FlowModeParam.FlowModeEnum.Purge.ToString(), StringComparison.OrdinalIgnoreCase))
|
||
return;
|
||
|
||
currentTmaFlowMode.Value = FlowModeParam.FlowModeEnum.Purge.ToString();
|
||
_isTmaNotInstall = true;
|
||
}
|
||
|
||
public void TabSelectionChanged()
|
||
{
|
||
UpdateRecipeFormat();
|
||
OnViewLoaded(View);
|
||
}
|
||
|
||
public void UpdateRecipeFormat()
|
||
{
|
||
var chamber = QueryDataClient.Instance.Service.GetConfig("System.Recipe.ChamberModules");
|
||
if (chamber == null)
|
||
{
|
||
chamber = "PM1";
|
||
}
|
||
|
||
Chambers = new ObservableCollection<string>(((string)chamber).Split(','));
|
||
if (Chambers.Count > 1)
|
||
{
|
||
for (var i = 0; i < Chambers.Count; i++)
|
||
{
|
||
var isPmInstall =
|
||
(bool)QueryDataClient.Instance.Service.GetConfig(
|
||
$"System.SetUp.Is{Chambers[i].ToString()}Installed");
|
||
{
|
||
if (!isPmInstall)
|
||
{
|
||
Chambers.RemoveAt(i);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (Chambers.Count == 0)
|
||
{
|
||
Chambers = new ObservableCollection<string>(new string[] { "PM1" });
|
||
}
|
||
|
||
SelectedChamber = Chambers[0];
|
||
|
||
if (DicColunms.Keys.Contains(CurrentProcessType))
|
||
{
|
||
Columns = DicColunms[CurrentProcessType];
|
||
}
|
||
else
|
||
{
|
||
Columns = _columnBuilder.Build($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, true,
|
||
BaseApp.Instance.UserContext.RoleName);
|
||
|
||
DicColunms[CurrentProcessType] = Columns;
|
||
}
|
||
|
||
CurrentRecipe = new RecipeData(_gasFlowCalculator);
|
||
CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
|
||
CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
|
||
|
||
_editMode = EditMode.None;
|
||
|
||
MultiChamberVisibility = Chambers.Count > 1 ? Visibility.Visible : Visibility.Collapsed;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Chamber变更时重新加载Recipe。
|
||
/// </summary>
|
||
public async void ChamberSelectionChanged()
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
||
DialogType.CONFIRM,
|
||
$"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
IsLoading = true;
|
||
|
||
await CurrentRecipe.ChangeChamber(Columns
|
||
, _columnBuilder.Configs, SelectedChamber, GetLoadingDispatcher());
|
||
|
||
IsLoading = false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 左侧Recipe列表选择改变时,重新加载Recipe。
|
||
/// </summary>
|
||
/// <param name="node"></param>
|
||
public async void TreeSelectChanged(FileNode node)
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
||
DialogType.CONFIRM,
|
||
$"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
CurrentFileNode = node;
|
||
|
||
if (node != null && node.IsFile)
|
||
{
|
||
await LoadData(node.PrefixPath, node.FullPath);
|
||
}
|
||
else
|
||
{
|
||
ClearData();
|
||
_editMode = EditMode.None;
|
||
}
|
||
|
||
UpdateView();
|
||
}
|
||
|
||
#region folder
|
||
|
||
public void NewFolder()
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
||
dialog.FileName = "new folder";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(name))
|
||
{
|
||
DialogBox.ShowWarning("Folder name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" +
|
||
ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
var processType = string.Empty;
|
||
var newFolder = string.Empty;
|
||
if (CurrentFileNode != null)
|
||
{
|
||
prefix = CurrentFileNode.PrefixPath;
|
||
var folder = CurrentFileNode.FullPath;
|
||
if (CurrentFileNode.IsFile)
|
||
{
|
||
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
||
if (!string.IsNullOrEmpty(folder))
|
||
newFolder = folder;
|
||
}
|
||
else
|
||
{
|
||
newFolder = folder + "\\";
|
||
}
|
||
|
||
}
|
||
|
||
newFolder = newFolder + name;
|
||
|
||
if (IsExist(newFolder, false))
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
if (newFolder.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
_recipeProvider.CreateRecipeFolder(prefix, newFolder);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
|
||
}
|
||
|
||
public void NewFolderRoot()
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
||
dialog.FileName = "new folder";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(name))
|
||
{
|
||
DialogBox.ShowWarning("Folder name should not be empty");
|
||
return;
|
||
}
|
||
|
||
|
||
if (IsExist(name, false))
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {name}, Folder with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
if (name.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {name}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
var prefix = ChamberType[ChamberTypeIndexSelection] + "\\" +
|
||
ProcessTypeFileList[ProcessTypeIndexSelection].ProcessType;
|
||
|
||
_recipeProvider.CreateRecipeFolder(prefix, name);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, name, true);
|
||
}
|
||
|
||
public void DeleteFolder()
|
||
{
|
||
if (CurrentFileNode == null || CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
if (CurrentFileNode.Files.Count > 0)
|
||
{
|
||
DialogBox.ShowWarning(
|
||
$"Can not delete non-empty folder, Remove the files or folders under \r\n{CurrentFileNode.FullPath}.");
|
||
return;
|
||
}
|
||
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
||
$"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
|
||
if (selection == DialogButton.No)
|
||
return;
|
||
|
||
var nextFocus = CurrentFileNode.Parent.FullPath;
|
||
var isFolder = true;
|
||
if (CurrentFileNode.Parent.Files.Count > 1)
|
||
{
|
||
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
||
{
|
||
if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
|
||
{
|
||
if (i == 0)
|
||
{
|
||
nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
|
||
isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
|
||
}
|
||
else
|
||
{
|
||
nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
|
||
isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
_recipeProvider.DeleteRecipeFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
|
||
}
|
||
|
||
public void RenameFolder()
|
||
{
|
||
if (CurrentFileNode == null || CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Folder Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var name = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(name))
|
||
return;
|
||
|
||
var newFolder = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
||
if (!string.IsNullOrEmpty(newFolder))
|
||
newFolder = newFolder + name;
|
||
else
|
||
newFolder = name;
|
||
|
||
if (newFolder == CurrentFileNode.FullPath)
|
||
return;
|
||
|
||
if (IsExist(newFolder, false))
|
||
{
|
||
DialogBox.ShowWarning($"Can not rename to {newFolder}, Folder with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
if (newFolder.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {newFolder}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
_recipeProvider.RenameFolder(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath, newFolder);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newFolder, true);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region recipe
|
||
|
||
public void NewRecipe()
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Name");
|
||
dialog.FileName = "";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
if (CurrentFileNode != null)
|
||
{
|
||
var folder = CurrentFileNode.FullPath;
|
||
|
||
|
||
if (CurrentFileNode.IsFile)
|
||
{
|
||
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
||
//if (!string.IsNullOrEmpty(folder))
|
||
// folder = folder;
|
||
}
|
||
else
|
||
{
|
||
folder = folder + "\\";
|
||
}
|
||
|
||
recipeName = folder + recipeName;
|
||
}
|
||
|
||
if (IsExist(recipeName, true))
|
||
{
|
||
DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
|
||
if (recipeName.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
var recipe = new RecipeData(_gasFlowCalculator);
|
||
recipe.Name = recipeName;
|
||
recipe.PrefixPath = prefix;
|
||
recipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.CreateTime = DateTime.Now;
|
||
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.ReviseTime = DateTime.Now;
|
||
recipe.Description = string.Empty;
|
||
|
||
if (!Save(recipe, true))
|
||
return;
|
||
|
||
var types = prefix.Split('\\');
|
||
|
||
ReloadRecipeFileList(types[0], types[1], recipeName, false);
|
||
|
||
}
|
||
|
||
public void NewRecipeRoot()
|
||
{
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = "new recipe";
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
if (IsExist(recipeName, true))
|
||
{
|
||
DialogBox.ShowWarning($"Can not create {recipeName}, Recipe with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
|
||
if (recipeName.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
var recipe = new RecipeData(_gasFlowCalculator);
|
||
recipe.Name = recipeName;
|
||
recipe.PrefixPath = CurrentChamberType + "\\" + CurrentProcessType;
|
||
recipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.CreateTime = DateTime.Now;
|
||
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.ReviseTime = DateTime.Now;
|
||
recipe.Description = string.Empty;
|
||
|
||
if (!Save(recipe, true))
|
||
return;
|
||
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
|
||
}
|
||
|
||
private void ReloadRecipeFileList(string chamberType, string processType, string selectedFile,
|
||
bool selectionIsFolder)
|
||
{
|
||
var item = ProcessTypeFileList.FirstOrDefault(x => x.ProcessType == processType);
|
||
if (item == null)
|
||
{
|
||
LOG.Write("error reload recipe file list, type = " + processType);
|
||
}
|
||
|
||
var prefix = $"{ChamberType[ChamberTypeIndexSelection]}\\{item.ProcessType}";
|
||
var recipes = _recipeProvider.GetXmlRecipeList(prefix);
|
||
|
||
item.FileListByProcessType =
|
||
RecipeSequenceTreeBuilder.BuildFileNode(prefix, selectedFile, selectionIsFolder, recipes)[0].Files;
|
||
item.FilterFileListByProcessType = item.FileListByProcessType;
|
||
|
||
item.InvokePropertyChanged();
|
||
}
|
||
|
||
private bool IsExist(string fullPath, bool isFile)
|
||
{
|
||
for (var i = 0; i < ProcessTypeFileList.Count; i++)
|
||
{
|
||
if (ProcessTypeFileList[i].ProcessType == CurrentProcessType)
|
||
{
|
||
if (ProcessTypeFileList[i].FileListByProcessType.Count == 0)
|
||
return false;
|
||
|
||
return FindFile(fullPath, ProcessTypeFileList[i].FileListByProcessType[0].Parent, isFile);
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
private bool FindFile(string path, FileNode root, bool isFile)
|
||
{
|
||
if (root.FullPath == path && !isFile)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
foreach (var node in root.Files)
|
||
{
|
||
if (isFile && node.IsFile && node.FullPath == path)
|
||
return true;
|
||
|
||
if (!node.IsFile && FindFile(path, node, isFile))
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
public void SaveAsRecipe()
|
||
{
|
||
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
|
||
var folder = CurrentFileNode.FullPath;
|
||
if (CurrentFileNode.IsFile)
|
||
{
|
||
folder = folder.Substring(0, folder.LastIndexOf("\\") + 1);
|
||
}
|
||
|
||
if (!string.IsNullOrEmpty(folder))
|
||
recipeName = folder + "\\" + recipeName;
|
||
|
||
if (CurrentFileNode.FullPath == recipeName)
|
||
return;
|
||
|
||
if (IsExist(recipeName, true))
|
||
{
|
||
DialogBox.ShowWarning($"Can not copy to {recipeName}, Recipe with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
|
||
if (recipeName.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {recipeName}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
CurrentRecipe.Creator = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.CreateTime = DateTime.Now;
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
CurrentRecipe.Description = CurrentRecipe.Description + ". Renamed from " + CurrentFileNode.Name;
|
||
|
||
_recipeProvider.SaveAsRecipe(prefix, recipeName, CurrentRecipe.GetXmlString());
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, recipeName, false);
|
||
}
|
||
|
||
public void RenameRecipe()
|
||
{
|
||
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
if (IsChanged)
|
||
{
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No | DialogButton.Cancel,
|
||
DialogType.CONFIRM, $"Recipe {CurrentRecipe.Name} is changed, do you want to save it?");
|
||
if (selection == DialogButton.Cancel)
|
||
return;
|
||
|
||
if (selection == DialogButton.Yes)
|
||
{
|
||
CurrentRecipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
CurrentRecipe.ReviseTime = DateTime.Now;
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
}
|
||
|
||
var dialog = new InputFileNameDialogViewModel("Input New Recipe Name");
|
||
dialog.FileName = CurrentFileNode.Name;
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var recipeName = dialog.FileName.Trim();
|
||
if (string.IsNullOrEmpty(dialog.FileName))
|
||
{
|
||
DialogBox.ShowWarning("Recipe file name should not be empty");
|
||
return;
|
||
}
|
||
|
||
var prefix = CurrentChamberType + "\\" + CurrentProcessType;
|
||
var processType = string.Empty;
|
||
|
||
var newName = CurrentFileNode.FullPath.Substring(0, CurrentFileNode.FullPath.LastIndexOf("\\") + 1);
|
||
if (!string.IsNullOrEmpty(newName))
|
||
newName = newName + recipeName;
|
||
else
|
||
newName = recipeName;
|
||
|
||
if (newName == CurrentFileNode.FullPath)
|
||
return;
|
||
|
||
if (IsExist(newName, true))
|
||
{
|
||
DialogBox.ShowWarning($"Can not rename to {newName}, Recipe with the same name already exist.");
|
||
return;
|
||
}
|
||
|
||
|
||
if (newName.Length > 200)
|
||
{
|
||
DialogBox.ShowWarning($"Can not create folder {newName}, Folder name too long, should be less 200.");
|
||
return;
|
||
}
|
||
|
||
_recipeProvider.RenameRecipe(prefix, CurrentFileNode.FullPath, newName);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, newName, false);
|
||
}
|
||
|
||
public void DeleteRecipe()
|
||
{
|
||
if (CurrentFileNode == null || !CurrentFileNode.IsFile)
|
||
return;
|
||
|
||
var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No, DialogType.CONFIRM,
|
||
$"Are you sure you want to delete \r\n {CurrentFileNode.FullPath}?");
|
||
if (selection == DialogButton.No)
|
||
return;
|
||
|
||
var nextFocus = CurrentFileNode.Parent.FullPath;
|
||
var isFolder = true;
|
||
if (CurrentFileNode.Parent.Files.Count > 1)
|
||
{
|
||
for (var i = 0; i < CurrentFileNode.Parent.Files.Count; i++)
|
||
{
|
||
if (CurrentFileNode.Parent.Files[i] == CurrentFileNode)
|
||
{
|
||
if (i == 0)
|
||
{
|
||
nextFocus = CurrentFileNode.Parent.Files[i + 1].FullPath;
|
||
isFolder = !CurrentFileNode.Parent.Files[i + 1].IsFile;
|
||
}
|
||
else
|
||
{
|
||
nextFocus = CurrentFileNode.Parent.Files[i - 1].FullPath;
|
||
isFolder = !CurrentFileNode.Parent.Files[i - 1].IsFile;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
_recipeProvider.DeleteRecipe(CurrentFileNode.PrefixPath, CurrentFileNode.FullPath);
|
||
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, nextFocus, isFolder);
|
||
}
|
||
|
||
public void RefreshRecipe()
|
||
{
|
||
ReloadRecipeFileList(CurrentChamberType, CurrentProcessType, "", false);
|
||
}
|
||
|
||
public async void ReloadRecipe()
|
||
{
|
||
if (_editMode == EditMode.Normal || _editMode == EditMode.Edit)
|
||
{
|
||
if (CurrentRecipe == null)
|
||
return;
|
||
|
||
if (CurrentRecipe.IsChanged)
|
||
{
|
||
var ret = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
||
DialogType.CONFIRM,
|
||
$"Recipe {CurrentRecipe.Name} has changed, discard and reload?");
|
||
if (ret == DialogButton.No)
|
||
return;
|
||
}
|
||
|
||
await LoadData(CurrentRecipe.PrefixPath, CurrentRecipe.Name);
|
||
UpdateView();
|
||
ValidateEntireRecipe();
|
||
|
||
// ValidateEntireRecipe()会重新计算比例相关的值,导致IsChanged == true, 刷新一下。
|
||
foreach (var step in CurrentRecipe.Steps)
|
||
step.Save();
|
||
}
|
||
}
|
||
|
||
public void SaveToAll()
|
||
{
|
||
ValidateEntireRecipe();
|
||
|
||
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
||
{
|
||
DialogBox.ShowWarning($"Saving failed, {CurrentRecipe.Name} is not a valid recipe file");
|
||
return;
|
||
}
|
||
|
||
//var selection = DialogBox.ShowDialog(DialogButton.Yes | DialogButton.No,
|
||
// DialogType.CONFIRM,
|
||
// $"Do you want to save to all chambers? \r\n This will replace all the other chambers recipe content");
|
||
//if (selection == DialogButton.No)
|
||
// return;
|
||
|
||
CurrentRecipe.SaveTo(Chambers.ToArray());
|
||
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
|
||
public void SaveTo()
|
||
{
|
||
ValidateEntireRecipe();
|
||
|
||
if (!CurrentRecipe.IsCompatibleWithCurrentFormat)
|
||
{
|
||
DialogBox.ShowWarning($"Saving failed, {CurrentRecipe.Name} is not a valid recipe file.");
|
||
return;
|
||
}
|
||
|
||
var dialog =
|
||
new SaveToDialogViewModel("Select the chamber to copy to", SelectedChamber, Chambers.ToList());
|
||
|
||
var wm = new WindowManager();
|
||
var dialogReturn = wm.ShowDialog(dialog);
|
||
if (!dialogReturn.HasValue || !dialogReturn.Value)
|
||
return;
|
||
|
||
var chambers = new List<string>();
|
||
foreach (var dialogChamber in dialog.Chambers)
|
||
{
|
||
if (dialogChamber.IsEnabled && dialogChamber.IsChecked)
|
||
chambers.Add(dialogChamber.Name);
|
||
}
|
||
|
||
if (chambers.Count == 0)
|
||
return;
|
||
|
||
CurrentRecipe.SaveTo(chambers.ToArray());
|
||
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Steps
|
||
|
||
/// <summary>
|
||
/// 展开DataGrid列组。
|
||
/// </summary>
|
||
/// <param name="col"></param>
|
||
public void ExpandColumnsGroup(ExpanderColumn col)
|
||
{
|
||
foreach (var subCol in col.ChildColumns)
|
||
{
|
||
subCol.UpdateVisibility();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 折叠DataGrid列组。
|
||
/// </summary>
|
||
/// <param name="col"></param>
|
||
public void CollapseColumnsGroup(ExpanderColumn col)
|
||
{
|
||
foreach (var subCol in col.ChildColumns)
|
||
{
|
||
subCol.Visibility = Visibility.Collapsed;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 检查是否所有的参数均有效。
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private bool CheckIfAllCellsValid(out string errorMessage)
|
||
{
|
||
errorMessage = string.Empty;
|
||
|
||
if (CurrentProcessType == ProcessTypeFileList[1].ProcessType)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
/*var lstError = new List<string>();*/
|
||
_validationResultList.Clear();
|
||
|
||
for (var a = 0; a < CurrentRecipe.Steps.Count; a++)
|
||
{
|
||
var invalidParam =
|
||
CurrentRecipe.Steps[a]
|
||
.Where(x => x is IParam p && p.IsValidated == false).ToList();
|
||
|
||
_validationResultList.AddRange(invalidParam.Cast<IParam>()
|
||
.Select(x => new RecipeStepValidationInfo(
|
||
_currentRecipe.Steps[a],
|
||
x,
|
||
x.ValidationError)));
|
||
}
|
||
|
||
if (_validationResultList.Count <= 0)
|
||
{
|
||
ErrorsCount = 0;
|
||
return true;
|
||
}
|
||
|
||
ErrorsCount = _validationResultList.Count;
|
||
|
||
var errCnt = 0;
|
||
var strInfo = new StringBuilder();
|
||
foreach (var t in _validationResultList)
|
||
{
|
||
strInfo.AppendLine(t.ToString());
|
||
errCnt++;
|
||
|
||
if (errCnt > 10)
|
||
break;
|
||
}
|
||
|
||
if (errCnt < _validationResultList.Count)
|
||
strInfo.AppendLine("\r\n<please check for more errors...>");
|
||
|
||
// MessageBox.Show(strInfo.ToString(), "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||
errorMessage = strInfo.ToString();
|
||
return false;
|
||
}
|
||
|
||
public void SaveRecipe()
|
||
{
|
||
/*if (Save(CurrentRecipe, false))
|
||
MessageBox.Show($"The recipe has been saved successfully!", "Succeeded", MessageBoxButton.OK,
|
||
MessageBoxImage.Information);*/
|
||
|
||
Save(CurrentRecipe, false);
|
||
}
|
||
|
||
public void PopSetting(string controlName, Param paramData)
|
||
{
|
||
var stepNum = Convert.ToInt32(((StepParam)paramData.Parent[1]).Value);
|
||
|
||
var dialog = new PublicPopSettingDialogViewModel();
|
||
dialog.DisplayName = paramData.DisplayName;
|
||
var Parameters = new RecipeStep(null);
|
||
|
||
Parameters = CurrentRecipe.PopSettingSteps[controlName][stepNum - 1];
|
||
|
||
var ControlParameters = new RecipeStep(null);
|
||
var BrandParameters = new ObservableCollection<BandParam>();
|
||
foreach (var item in Parameters)
|
||
{
|
||
if (item.Name.Contains("Band"))
|
||
{
|
||
var name = item.Name.Replace("Wavelength", "").Replace("Bandwidth", "");
|
||
var displayName = item.DisplayName.Replace("Wavelength", "").Replace("Bandwidth", "");
|
||
|
||
if (BrandParameters.Where(x => x.Name == name).Count() == 0)
|
||
{
|
||
BrandParameters.Add(new BandParam()
|
||
{
|
||
Name = name,
|
||
DisplayName = displayName
|
||
});
|
||
}
|
||
|
||
if (item.Name.Contains("Wavelength"))
|
||
{
|
||
BrandParameters.First(x => x.Name == name).WavelengthDoubleParam = item;
|
||
}
|
||
else if (item.Name.Contains("Bandwidth"))
|
||
{
|
||
BrandParameters.First(x => x.Name == name).BandwidthDoubleParam = item;
|
||
}
|
||
}
|
||
else
|
||
ControlParameters.Add(item);
|
||
}
|
||
|
||
dialog.Parameters = Parameters;
|
||
dialog.ControlParameters = ControlParameters;
|
||
dialog.BandParameters = BrandParameters;
|
||
|
||
var wm = new WindowManager();
|
||
var bret = wm.ShowDialog(dialog);
|
||
if (bret == true)
|
||
{
|
||
CurrentRecipe.PopSettingSteps[controlName][stepNum - 1] = dialog.Parameters;
|
||
}
|
||
}
|
||
|
||
private bool Save(RecipeData recipe, bool createNew)
|
||
{
|
||
if (string.IsNullOrEmpty(recipe.Name))
|
||
{
|
||
MessageBox.Show("Recipe name can't be empty", "Error",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return false;
|
||
}
|
||
|
||
ValidateEntireRecipe();
|
||
|
||
if (CheckIfAllCellsValid(out var errors) == false)
|
||
{
|
||
var mbr = MessageBox.Show($"{errors}\r\n Are you sure to continue to save?", "Warning",
|
||
MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||
if (mbr == MessageBoxResult.No)
|
||
return false;
|
||
}
|
||
|
||
var result = false;
|
||
|
||
|
||
recipe.Revisor = BaseApp.Instance.UserContext.LoginName;
|
||
recipe.ReviseTime = DateTime.Now;
|
||
|
||
result = _recipeProvider.WriteRecipeFile(recipe.PrefixPath, recipe.Name, recipe.GetXmlString());
|
||
|
||
if (result)
|
||
{
|
||
recipe.DataSaved();
|
||
|
||
_editMode = EditMode.Normal;
|
||
|
||
UpdateView();
|
||
}
|
||
else
|
||
{
|
||
MessageBox.Show("Save failed!");
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
public void AddStep()
|
||
{
|
||
Columns.Clear();
|
||
//add时重新从配方中加载数据
|
||
Columns = _columnBuilder.Build($"{CurrentChamberType}\\{CurrentProcessType}", SelectedChamber, true, BaseApp.Instance.UserContext.RoleName);
|
||
|
||
CurrentRecipe.Steps.Add(CurrentRecipe.CreateStep(Columns));
|
||
|
||
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
||
_editMode = EditMode.Edit;
|
||
|
||
ValidateEntireRecipe();
|
||
CheckIfAllCellsValid(out _);
|
||
UpdateView();
|
||
}
|
||
|
||
public void InsertStepToLeft()
|
||
{
|
||
if (SelectedRecipeSteps.Count != 1)
|
||
return;
|
||
|
||
var stepNo = SelectedRecipeSteps[0]?.StepNo;
|
||
if (RecipeStep.ValidateStepNo(stepNo, out var vStepNo) == false)
|
||
return;
|
||
|
||
|
||
var index = vStepNo - RecipeStep.START_INDEX;
|
||
|
||
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
||
_editMode = EditMode.Edit;
|
||
|
||
CurrentRecipe.Steps.Insert(index, CurrentRecipe.CreateStep(Columns));
|
||
}
|
||
|
||
public void InsertStepToRight()
|
||
{
|
||
if (SelectedRecipeSteps.Count != 1)
|
||
return;
|
||
|
||
var stepNo = SelectedRecipeSteps[0]?.StepNo;
|
||
if (RecipeStep.ValidateStepNo(stepNo, out var vStepNo) == false)
|
||
return;
|
||
|
||
var index = vStepNo - RecipeStep.START_INDEX;
|
||
|
||
|
||
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
||
_editMode = EditMode.Edit;
|
||
|
||
if (index < _currentRecipe.Steps.Count - 1)
|
||
CurrentRecipe.Steps.Insert(index + 1, CurrentRecipe.CreateStep(Columns));
|
||
else
|
||
CurrentRecipe.Steps.Add(CurrentRecipe.CreateStep(Columns));
|
||
|
||
}
|
||
|
||
private readonly RecipeStepCollection _copySteps =
|
||
new RecipeStepCollection();
|
||
|
||
private readonly Dictionary<string, ObservableCollection<RecipeStep>> _popCopySteps =
|
||
new Dictionary<string, ObservableCollection<RecipeStep>>();
|
||
|
||
|
||
/// <summary>
|
||
/// 拷贝所有选中的Steps。
|
||
/// </summary>
|
||
/// <param name="steps"></param>
|
||
public void CopyStep()
|
||
{
|
||
_copySteps.Clear();
|
||
_popCopySteps.Clear();
|
||
|
||
if (SelectedRecipeSteps == null || SelectedRecipeSteps.Count <= 0)
|
||
return;
|
||
|
||
foreach (var step in SelectedRecipeSteps)
|
||
_copySteps.Add(_currentRecipe.CloneStep(Columns, step));
|
||
|
||
CurrentRecipe.ValidLoopData();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在左侧粘贴Step。
|
||
/// </summary>
|
||
public async void PasteStepToLeft()
|
||
{
|
||
await Paste(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在右侧粘贴Step。
|
||
/// </summary>
|
||
public async void PasteStepToRight()
|
||
{
|
||
await Paste(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 粘贴Step。
|
||
/// <para>注意:async Task 标记的方法不能直接应用于Caliburn.Message.Attach 方法。</para>
|
||
/// </summary>
|
||
/// <param name="isToLeft">是否粘贴到当前选中的Step的左侧。</param>
|
||
/// <returns></returns>
|
||
private async Task Paste(bool isToLeft)
|
||
{
|
||
if (SelectedRecipeSteps == null || SelectedRecipeSteps.Count != 1)
|
||
return;
|
||
|
||
if (_copySteps.Count <= 0)
|
||
return;
|
||
|
||
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
||
_editMode = EditMode.Edit;
|
||
|
||
var stepNo = SelectedRecipeSteps[0].StepNo;
|
||
if (RecipeStep.ValidateStepNo(stepNo, out var vStepNo) == false)
|
||
return;
|
||
|
||
foreach (var t in _copySteps)
|
||
{
|
||
var cloned = CurrentRecipe.CloneStep(Columns, t);
|
||
|
||
var pos = isToLeft ? vStepNo - RecipeStep.START_INDEX : vStepNo;
|
||
|
||
await Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
|
||
(Action)(() => { CurrentRecipe.Steps.Insert(pos, cloned); }));
|
||
}
|
||
|
||
ValidateEntireRecipe();
|
||
CurrentRecipe.ValidLoopData();
|
||
CheckIfAllCellsValid(out _);
|
||
UpdateView();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在左侧复制Step。
|
||
/// </summary>
|
||
public async void DuplicateStepToLeft()
|
||
{
|
||
await Duplicate(true);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在右侧复制Step。
|
||
/// </summary>
|
||
public async void DuplicateStepToRight()
|
||
{
|
||
await Duplicate(false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 复制选中的Step。
|
||
/// </summary>
|
||
/// <param name="isToLeft">是否复制到选中的Step的左侧。</param>
|
||
private async Task Duplicate(bool isToLeft)
|
||
{
|
||
if (SelectedRecipeSteps == null || SelectedRecipeSteps.Count != 1)
|
||
return;
|
||
|
||
CopyStep();
|
||
await Paste(isToLeft);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 删除步骤。
|
||
/// </summary>
|
||
public void DeleteStep()
|
||
{
|
||
|
||
if (_editMode != EditMode.New && _editMode != EditMode.ReName)
|
||
_editMode = EditMode.Edit;
|
||
|
||
for (var i = SelectedRecipeSteps.Count - 1; i >= 0; i--)
|
||
{
|
||
_currentRecipe.Steps.Remove(SelectedRecipeSteps[i]);
|
||
}
|
||
|
||
CheckIfAllCellsValid(out _);
|
||
|
||
}
|
||
|
||
private void CreateValidationDetailWindow()
|
||
{
|
||
_winValidationInfo = new RecipeEditorValidationDetailWindow(_validationResultList, _lastPosOfValidationWin);
|
||
_winValidationInfo.DataContext = this;
|
||
_winValidationInfo.Closed += (sender, args) =>
|
||
{
|
||
_lastPosOfValidationWin = new Point(_winValidationInfo.Left, _winValidationInfo.Top);
|
||
ResetHighlight();
|
||
};
|
||
}
|
||
|
||
public void ShowValidationDetailWindow()
|
||
{
|
||
ValidateEntireRecipe();
|
||
CheckIfAllCellsValid(out _);
|
||
|
||
if (Application.Current.Windows.OfType<RecipeEditorValidationDetailWindow>().Any())
|
||
_winValidationInfo.Activate();
|
||
else
|
||
{
|
||
CreateValidationDetailWindow();
|
||
_winValidationInfo.Show();
|
||
}
|
||
}
|
||
|
||
public void ShowHideParamValues()
|
||
{
|
||
CurrentRecipe.Steps.IsHideValue = !CurrentRecipe.Steps.IsHideValue;
|
||
}
|
||
|
||
private TreeViewItem GetParentObjectEx<TreeViewItem>(DependencyObject obj) where TreeViewItem : FrameworkElement
|
||
{
|
||
var parent = VisualTreeHelper.GetParent(obj);
|
||
while (parent != null)
|
||
{
|
||
if (parent is TreeViewItem)
|
||
{
|
||
return (TreeViewItem)parent;
|
||
}
|
||
|
||
parent = VisualTreeHelper.GetParent(parent);
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
public void TreeRightMouseDown(MouseButtonEventArgs e)
|
||
{
|
||
var item = GetParentObjectEx<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
|
||
if (item != null)
|
||
{
|
||
item.Focus();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 在DataGrid中聚焦并高亮指定的参数。
|
||
/// </summary>
|
||
/// <param name="param"></param>
|
||
public void FocusToParam(IParam param)
|
||
{
|
||
if (param == null)
|
||
return;
|
||
|
||
ResetHighlight();
|
||
|
||
var row = param.RowOwner;
|
||
var col = param.ColumnOwner;
|
||
|
||
if (row != null && col != null)
|
||
{
|
||
((RecipeEditorView)View).dgCustom.ScrollIntoView(param.Parent, col);
|
||
param.Highlight();
|
||
}
|
||
}
|
||
|
||
|
||
public void ResetHighlight()
|
||
{
|
||
_currentRecipe.Steps.ResetHighlight();
|
||
}
|
||
|
||
#endregion
|
||
|
||
private void ClearData()
|
||
{
|
||
_editMode = EditMode.None;
|
||
CurrentRecipe.Clear();
|
||
CurrentRecipe.Name = string.Empty;
|
||
CurrentRecipe.Description = string.Empty;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 根据配置获取Cascade方式呈现Recipe的Dispatcher,或返回null。
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static Dispatcher GetLoadingDispatcher()
|
||
{
|
||
// 判断Step呈现方式
|
||
var isCascadeLoading = (bool)QueryDataClient.Instance.Service.GetConfig("System.Recipe.CascadeLoading");
|
||
var dispatcher = isCascadeLoading ? Dispatcher.CurrentDispatcher : null;
|
||
return dispatcher;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 从配置文件中获取是否加载Recipe后自动隐藏参数值的配置。
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private static bool GetIsHideValueAfterLoading()
|
||
{
|
||
try
|
||
{
|
||
return false;
|
||
//return (bool)QueryDataClient.Instance.Service.GetConfig("System.Recipe.HideParamValueAfterLoading");
|
||
}
|
||
catch
|
||
{
|
||
// 如果没有找到参数,默认隐藏参数值。
|
||
return false;
|
||
}
|
||
|
||
}
|
||
|
||
private async Task LoadData(string prefixPath, string recipeName)
|
||
{
|
||
var dg = ((RecipeEditorView)View).dgCustom;
|
||
|
||
IsLoading = true;
|
||
|
||
CurrentRecipe.Clear();
|
||
CurrentRecipe.Steps.Save(); // 重置为已保存状态
|
||
ErrorsCount = 0;
|
||
|
||
var recipeContent = _recipeProvider.ReadRecipeFile(prefixPath, recipeName);
|
||
|
||
if (string.IsNullOrEmpty(recipeContent))
|
||
{
|
||
MessageBox.Show($"{prefixPath}\\{recipeName} is empty, please confirm the file is valid.",
|
||
"Error",
|
||
MessageBoxButton.OK, MessageBoxImage.Error);
|
||
return;
|
||
}
|
||
|
||
CurrentRecipe.RecipeChamberType = _columnBuilder.RecipeChamberType;
|
||
CurrentRecipe.RecipeVersion = _columnBuilder.RecipeVersion;
|
||
CurrentRecipe.Steps.IsHideValue = GetIsHideValueAfterLoading();
|
||
|
||
await CurrentRecipe.InitData(prefixPath, recipeName, recipeContent, Columns,
|
||
_columnBuilder.Configs, SelectedChamber, GetLoadingDispatcher());
|
||
|
||
_editMode = EditMode.Normal;
|
||
|
||
IsLoading = false;
|
||
|
||
// 如果当前Recipe非本机Recipe,比例相关的参数可能由于算法不同导致结果不同,
|
||
// 重新计算一次Recipe,以更新比例计算值,并校验其合法性。
|
||
ValidateEntireRecipe();
|
||
CheckIfAllCellsValid(out var _);
|
||
}
|
||
|
||
private void UpdateView()
|
||
{
|
||
var isFileSelected = CurrentFileNode != null && CurrentFileNode.IsFile;
|
||
|
||
EnableNew = isFileSelected;
|
||
EnableReName = isFileSelected;
|
||
EnableCopy = isFileSelected;
|
||
EnableDelete = isFileSelected;
|
||
EnableSave = isFileSelected;
|
||
EnableStep = isFileSelected;
|
||
EnableSaveTo = isFileSelected;
|
||
EnableSaveToAll = isFileSelected;
|
||
|
||
if (_editMode == EditMode.None)
|
||
{
|
||
EnableNew = true;
|
||
EnableReName = false;
|
||
EnableCopy = false;
|
||
EnableDelete = false;
|
||
EnableStep = false;
|
||
EnableSave = false;
|
||
EnableReload = true;
|
||
|
||
}
|
||
|
||
NotifyOfPropertyChange(nameof(EnableNew));
|
||
NotifyOfPropertyChange(nameof(EnableReName));
|
||
NotifyOfPropertyChange(nameof(EnableCopy));
|
||
NotifyOfPropertyChange(nameof(EnableDelete));
|
||
NotifyOfPropertyChange(nameof(EnableSave));
|
||
NotifyOfPropertyChange(nameof(EnableStep));
|
||
NotifyOfPropertyChange(nameof(EnableSaveTo));
|
||
NotifyOfPropertyChange(nameof(EnableSaveToAll));
|
||
NotifyOfPropertyChange(nameof(EnableReload));
|
||
|
||
NotifyOfPropertyChange(nameof(CurrentRecipe));
|
||
}
|
||
|
||
private string _currentCriteria = string.Empty;
|
||
|
||
public string CurrentCriteria
|
||
{
|
||
get => _currentCriteria;
|
||
set
|
||
{
|
||
if (value == _currentCriteria)
|
||
return;
|
||
|
||
_currentCriteria = value;
|
||
NotifyOfPropertyChange(nameof(CurrentCriteria));
|
||
ApplyFilter();
|
||
}
|
||
}
|
||
|
||
private void ApplyFilter()
|
||
{
|
||
ProcessTypeFileList[ProcessTypeIndexSelection].FilterFileListByProcessType =
|
||
new ObservableCollection<FileNode>(ProcessTypeFileList[ProcessTypeIndexSelection].FileListByProcessType
|
||
.Where(d => d.Name.IndexOf(CurrentCriteria, StringComparison.OrdinalIgnoreCase) >= 0));
|
||
}
|
||
|
||
public void ClearFilter()
|
||
{
|
||
CurrentCriteria = "";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当主窗口状态Login状态发生变化时处理当前窗口状态。
|
||
/// </summary>
|
||
/// <param name="message"></param>
|
||
public void Handle(UserMode message)
|
||
{
|
||
switch (message)
|
||
{
|
||
case UserMode.None:
|
||
break;
|
||
case UserMode.Normal:
|
||
break;
|
||
case UserMode.Lock:
|
||
case UserMode.Logoff:
|
||
case UserMode.Exit:
|
||
case UserMode.Shutdown:
|
||
case UserMode.Breakdown:
|
||
_winValidationInfo?.Close();
|
||
break;
|
||
|
||
default:
|
||
// ignore
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|