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> _signalMap = new Dictionary>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary _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 signals; if (!_signalMap.TryGetValue(key, out signals)) { signals = new List(); _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 points) { if (points == null) { return; } foreach (var point in points) { if (point == null) { continue; } List 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 GetSignals(string pointReference) { var definition = ResolveDefinition(pointReference); var key = definition != null ? definition.PointKey : pointReference; if (string.IsNullOrWhiteSpace(key)) { return Enumerable.Empty(); } List signals; if (_signalMap.TryGetValue(key, out signals)) { return signals; } return Enumerable.Empty(); } 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 "单输出控制"; } } } }