306 lines
11 KiB
C#
306 lines
11 KiB
C#
using MainShell.DeviceMaintance.Model;
|
|
using MainShell.DeviceMaintance.ViewModel.State;
|
|
using MainShell.Hardware;
|
|
using MainShell.Manual.ViewModel.State;
|
|
using MaxwellFramework.Core.Interfaces;
|
|
using Stylet;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MainShell.DeviceMaintance.ViewModel
|
|
{
|
|
public class CylinderViewModel : Screen, IPage
|
|
{
|
|
private readonly IDeviceIoMonitorService _ioMonitorService;
|
|
private readonly IDeviceCylinderService _cylinderService;
|
|
private readonly Dictionary<string, List<CylinderSignalState>> _signalMap = new Dictionary<string, List<CylinderSignalState>>(StringComparer.OrdinalIgnoreCase);
|
|
private readonly Dictionary<string, DeviceIoPointDefinition> _ioDefinitionsByName;
|
|
|
|
private CylinderPageState _pageState;
|
|
public CylinderPageState PageState
|
|
{
|
|
get { return _pageState; }
|
|
set { SetAndNotify(ref _pageState, value); }
|
|
}
|
|
|
|
public CylinderViewModel(IDeviceIoMonitorService ioMonitorService, IDeviceCylinderService cylinderService)
|
|
{
|
|
_ioMonitorService = ioMonitorService;
|
|
_cylinderService = cylinderService;
|
|
_ioDefinitionsByName = _ioMonitorService.Definitions.ToDictionary(x => x.Name, x => x, StringComparer.OrdinalIgnoreCase);
|
|
PageState = BuildState();
|
|
_ioMonitorService.IoChanged += OnIoChanged;
|
|
_ioMonitorService.Start();
|
|
}
|
|
|
|
protected override void OnViewLoaded()
|
|
{
|
|
base.OnViewLoaded();
|
|
ApplyIoPoints(_ioMonitorService.LatestPoints.Values);
|
|
InitializePointsAsync();
|
|
}
|
|
|
|
protected override void OnDeactivate()
|
|
{
|
|
_ioMonitorService.IoChanged -= OnIoChanged;
|
|
base.OnDeactivate();
|
|
}
|
|
|
|
private CylinderPageState BuildState()
|
|
{
|
|
var state = new CylinderPageState();
|
|
_signalMap.Clear();
|
|
|
|
foreach (var definition in _cylinderService.Definitions)
|
|
{
|
|
var item = new CylinderItemState
|
|
{
|
|
Name = definition.Name,
|
|
Description = definition.Description,
|
|
Module = definition.Module,
|
|
ControlTypeText = GetControlTypeText(definition.ControlType)
|
|
};
|
|
|
|
item.ExtendCommand = new ActionCommand(() => ExecuteCylinderAction(definition, item, true), () => !item.IsBusy);
|
|
item.RetractCommand = new ActionCommand(() => ExecuteCylinderAction(definition, item, false), () => !item.IsBusy);
|
|
|
|
for (var i = 0; i < definition.ExtendOutputPoints.Count; i++)
|
|
{
|
|
AddOutputSignal(item, definition.ExtendOutputPoints[i], definition.ExtendOutputPoints.Count > 1 ? string.Format("{0}-伸出输出{1}", definition.Name, i + 1) : definition.Name + "-伸出输出");
|
|
}
|
|
|
|
for (var i = 0; i < definition.RetractOutputPoints.Count; i++)
|
|
{
|
|
AddOutputSignal(item, definition.RetractOutputPoints[i], definition.RetractOutputPoints.Count > 1 ? string.Format("{0}-缩回输出{1}", definition.Name, i + 1) : definition.Name + "-缩回输出");
|
|
}
|
|
|
|
foreach (var pointReference in definition.ExtendedFeedbackPoints)
|
|
{
|
|
AddFeedbackSignal(item, pointReference, definition.Name + "-伸出到位");
|
|
}
|
|
|
|
foreach (var pointReference in definition.RetractedFeedbackPoints)
|
|
{
|
|
AddFeedbackSignal(item, pointReference, definition.Name + "-缩回到位");
|
|
}
|
|
|
|
state.Cylinders.Add(item);
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
private void AddOutputSignal(CylinderItemState item, string pointReference, string fallbackName)
|
|
{
|
|
var definition = ResolveDefinition(pointReference);
|
|
var signal = new CylinderSignalState
|
|
{
|
|
PointReference = pointReference,
|
|
PointKey = definition?.PointKey,
|
|
Name = definition != null ? definition.Name : fallbackName,
|
|
LineNo = definition != null ? definition.LineNo : string.Empty,
|
|
IsOutput = true
|
|
};
|
|
item.OutputSignals.Add(signal);
|
|
MapSignal(signal, pointReference);
|
|
}
|
|
|
|
private void AddFeedbackSignal(CylinderItemState item, string pointReference, string fallbackName)
|
|
{
|
|
var definition = ResolveDefinition(pointReference);
|
|
var signal = new CylinderSignalState
|
|
{
|
|
PointReference = pointReference,
|
|
PointKey = definition?.PointKey,
|
|
Name = definition != null ? definition.Name : fallbackName,
|
|
LineNo = definition != null ? definition.LineNo : string.Empty,
|
|
IsOutput = false
|
|
};
|
|
item.FeedbackSignals.Add(signal);
|
|
MapSignal(signal, pointReference);
|
|
}
|
|
|
|
private DeviceIoPointDefinition ResolveDefinition(string pointReference)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(pointReference))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
DeviceIoPointDefinition definition;
|
|
if (_ioDefinitionsByName.TryGetValue(pointReference, out definition))
|
|
{
|
|
return definition;
|
|
}
|
|
|
|
int id;
|
|
if (!int.TryParse(pointReference, out id))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var matches = _ioMonitorService.Definitions.Where(x => x.Id == id).Take(2).ToList();
|
|
return matches.Count == 1 ? matches[0] : null;
|
|
}
|
|
|
|
private void MapSignal(CylinderSignalState signal, string pointReference)
|
|
{
|
|
var key = !string.IsNullOrWhiteSpace(signal.PointKey) ? signal.PointKey : pointReference;
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
return;
|
|
}
|
|
|
|
List<CylinderSignalState> signals;
|
|
if (!_signalMap.TryGetValue(key, out signals))
|
|
{
|
|
signals = new List<CylinderSignalState>();
|
|
_signalMap[key] = signals;
|
|
}
|
|
|
|
signals.Add(signal);
|
|
}
|
|
|
|
private void OnIoChanged(object sender, EventArgs e)
|
|
{
|
|
var args = e as MainShell.EventArgsFolder.DeviceIoChangedEventArgs;
|
|
if (args == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ApplyIoPoints(args.ChangedPoints);
|
|
}
|
|
|
|
private async void InitializePointsAsync()
|
|
{
|
|
_ioMonitorService.RequestRefresh();
|
|
await Task.Delay(150);
|
|
ApplyIoPoints(_ioMonitorService.LatestPoints.Values);
|
|
}
|
|
|
|
private void ApplyIoPoints(IEnumerable<DeviceIoPointState> points)
|
|
{
|
|
if (points == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var point in points)
|
|
{
|
|
if (point == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
List<CylinderSignalState> signals;
|
|
if (!_signalMap.TryGetValue(point.PointKey, out signals))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var signal in signals)
|
|
{
|
|
signal.IsOn = point.Value;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ExecuteCylinderAction(CylinderDefinition definition, CylinderItemState item, bool extend)
|
|
{
|
|
item.IsBusy = true;
|
|
RaiseCommands(item);
|
|
|
|
string failureReason;
|
|
var result = extend ? _cylinderService.TryExtend(definition.Name, out failureReason) : _cylinderService.TryRetract(definition.Name, out failureReason);
|
|
|
|
if (result)
|
|
{
|
|
SimulateCylinderFeedback(definition, extend);
|
|
PageState.LastActionMessage = definition.Name + (extend ? " 执行伸出成功。" : " 执行缩回成功。");
|
|
}
|
|
else
|
|
{
|
|
PageState.LastActionMessage = string.IsNullOrWhiteSpace(failureReason)
|
|
? definition.Name + (extend ? " 伸出失败。" : " 缩回失败。")
|
|
: failureReason;
|
|
}
|
|
|
|
PageState.LastActionTime = DateTime.Now;
|
|
item.IsBusy = false;
|
|
RaiseCommands(item);
|
|
}
|
|
|
|
private void SimulateCylinderFeedback(CylinderDefinition definition, bool extend)
|
|
{
|
|
foreach (var output in definition.ExtendOutputPoints.SelectMany(GetSignals))
|
|
{
|
|
output.IsOn = extend;
|
|
}
|
|
|
|
foreach (var output in definition.RetractOutputPoints.SelectMany(GetSignals))
|
|
{
|
|
output.IsOn = !extend;
|
|
}
|
|
|
|
foreach (var feedback in definition.ExtendedFeedbackPoints.SelectMany(GetSignals))
|
|
{
|
|
feedback.IsOn = extend;
|
|
}
|
|
|
|
foreach (var feedback in definition.RetractedFeedbackPoints.SelectMany(GetSignals))
|
|
{
|
|
feedback.IsOn = !extend;
|
|
}
|
|
}
|
|
|
|
private IEnumerable<CylinderSignalState> GetSignals(string pointReference)
|
|
{
|
|
var definition = ResolveDefinition(pointReference);
|
|
var key = definition != null ? definition.PointKey : pointReference;
|
|
if (string.IsNullOrWhiteSpace(key))
|
|
{
|
|
return Enumerable.Empty<CylinderSignalState>();
|
|
}
|
|
|
|
List<CylinderSignalState> signals;
|
|
if (_signalMap.TryGetValue(key, out signals))
|
|
{
|
|
return signals;
|
|
}
|
|
|
|
return Enumerable.Empty<CylinderSignalState>();
|
|
}
|
|
|
|
private static void RaiseCommands(CylinderItemState item)
|
|
{
|
|
var extend = item.ExtendCommand as ActionCommand;
|
|
if (extend != null)
|
|
{
|
|
extend.RaiseCanExecuteChanged();
|
|
}
|
|
|
|
var retract = item.RetractCommand as ActionCommand;
|
|
if (retract != null)
|
|
{
|
|
retract.RaiseCanExecuteChanged();
|
|
}
|
|
}
|
|
|
|
private static string GetControlTypeText(CylinderControlType controlType)
|
|
{
|
|
switch (controlType)
|
|
{
|
|
case CylinderControlType.DualOutput:
|
|
return "双输出控制";
|
|
case CylinderControlType.MultiOutput:
|
|
return "多输出单控";
|
|
default:
|
|
return "单输出控制";
|
|
}
|
|
}
|
|
}
|
|
}
|