aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs')
-rw-r--r--Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs1124
1 files changed, 1124 insertions, 0 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs
new file mode 100644
index 000000000..6ccc1caa0
--- /dev/null
+++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Technician/ViewModels/MachineTechViewVM.cs
@@ -0,0 +1,1124 @@
+using GalaSoft.MvvmLight.Ioc;
+using Google.Protobuf.Collections;
+using Microsoft.Win32;
+using RealTimeGraphEx.Controllers;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+using Tango.Core.Helpers;
+using Tango.Editors;
+using Tango.Integration.Observables;
+using Tango.Integration.Observables.Enumerations;
+using Tango.Integration.Operators;
+using Tango.MachineStudio.Common.Notifications;
+using Tango.MachineStudio.Common.StudioApplication;
+using Tango.MachineStudio.Technician.Editors;
+using Tango.MachineStudio.Technician.Project;
+using Tango.MachineStudio.Technician.TechItems;
+using Tango.PMR.Diagnostics;
+using Tango.Settings;
+using Tango.SharedUI;
+
+namespace Tango.MachineStudio.Technician.ViewModels
+{
+ /// <summary>
+ /// Represents the MachineTechView View Model.
+ /// </summary>
+ /// <seealso cref="Tango.SharedUI.ViewModel" />
+ /// <seealso cref="Tango.MachineStudio.Common.StudioApplication.IShutdownListener" />
+ public class MachineTechViewVM : ViewModel, IShutdownListener
+ {
+ private List<PropertyInfo> _diagnoticsDataProperties;
+ private Dictionary<SingleGraphItem, GraphController> _singleControllers;
+ private Dictionary<MultiGraphItem, GraphMultiController> _multiControllers;
+ private static object _elementsLock = new object();
+ private String _lastTechProjectFile;
+ private INotificationProvider _notification;
+ private DateTime _lastDiagnosticsResponseUpdate;
+ private const int MIN_DIAGNOSTICS_UPDATE_MILI = 500;
+
+ #region Properties
+
+ private ObservableCollection<IElementEditor> _elements;
+ /// <summary>
+ /// Gets or sets the visual elements.
+ /// </summary>
+ public ObservableCollection<IElementEditor> Elements
+ {
+ get { return _elements; }
+ set { _elements = value; RaisePropertyChangedAuto(); }
+ }
+
+ private ObservableCollection<TechItem> _availableTechItems;
+ /// <summary>
+ /// Gets or sets the available tech items.
+ /// </summary>
+ public ObservableCollection<TechItem> AvailableTechItems
+ {
+ get { return _availableTechItems; }
+ set { _availableTechItems = value; RaisePropertyChangedAuto(); }
+ }
+
+ private TechItem _selectedTechItem;
+ /// <summary>
+ /// Gets or sets the selected available tech item.
+ /// </summary>
+ public TechItem SelectedTechItem
+ {
+ get { return _selectedTechItem; }
+ set { _selectedTechItem = value; RaisePropertyChangedAuto(); }
+ }
+
+ /// <summary>
+ /// Gets or sets the db adapter.
+ /// </summary>
+ public ObservablesEntitiesAdapter Adapter { get; set; }
+
+ /// <summary>
+ /// Gets or sets the application manager.
+ /// </summary>
+ public IStudioApplicationManager ApplicationManager { get; set; }
+
+ private IMachineOperator _machineOperator;
+ /// <summary>
+ /// Gets or sets the machine operator.
+ /// </summary>
+ public IMachineOperator MachineOperator
+ {
+ get { return _machineOperator; }
+ set { _machineOperator = value; RaisePropertyChangedAuto(); }
+ }
+
+ private bool _disableRendering;
+ /// <summary>
+ /// Gets or sets a value indicating whether [disable rendering].
+ /// </summary>
+ public bool DisableRendering
+ {
+ get { return _disableRendering; }
+ set { _disableRendering = value; RaisePropertyChangedAuto(); OnDisableRenderingChanged(); }
+ }
+
+ private bool _hideMenu;
+ /// <summary>
+ /// Gets or sets a value indicating whether [hide menu].
+ /// </summary>
+ public bool HideMenu
+ {
+ get { return _hideMenu; }
+ set { _hideMenu = value; RaisePropertyChangedAuto(); }
+ }
+
+ private PushDiagnosticsResponse _currentDiagnosticsResponse;
+ /// <summary>
+ /// Gets or sets the current diagnostics response.
+ /// </summary>
+ public PushDiagnosticsResponse CurrentDiagnosticsResponse
+ {
+ get { return _currentDiagnosticsResponse; }
+ set { _currentDiagnosticsResponse = value; RaisePropertyChanged(nameof(CurrentDiagnosticsResponse)); }
+ }
+
+ private int _currentDiagnosticsResponseSize;
+ /// <summary>
+ /// Gets or sets the size of the current diagnostics response.
+ /// </summary>
+ /// <value>
+ /// The size of the current diagnostics response.
+ /// </value>
+ public int CurrentDiagnosticsResponseSize
+ {
+ get { return _currentDiagnosticsResponseSize; }
+ set { _currentDiagnosticsResponseSize = value; RaisePropertyChanged(nameof(CurrentDiagnosticsResponseSize)); }
+ }
+
+ #endregion
+
+ #region Commands
+
+ /// <summary>
+ /// Gets or sets the save as project command.
+ /// </summary>
+ public RelayCommand SaveAsProjectCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the save project command.
+ /// </summary>
+ public RelayCommand SaveProjectCommand { get; set; }
+
+ /// <summary>
+ /// Gets or sets the open project command.
+ /// </summary>
+ public RelayCommand OpenProjectCommand { get; set; }
+
+ #endregion
+
+ #region Constructors
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MachineTechViewVM"/> class.
+ /// </summary>
+ /// <param name="applicationManager">The application manager.</param>
+ /// <param name="notificationProvider">The notification provider.</param>
+ [PreferredConstructor]
+ public MachineTechViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider) : this(applicationManager, notificationProvider, true)
+ {
+
+ }
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="MachineTechViewVM"/> class.
+ /// </summary>
+ /// <param name="applicationManager">The application manager.</param>
+ /// <param name="notificationProvider">The notification provider.</param>
+ /// <param name="loadLastProject">if set to <c>true</c> [load last project].</param>
+ public MachineTechViewVM(IStudioApplicationManager applicationManager, INotificationProvider notificationProvider, bool loadLastProject)
+ {
+ _notification = notificationProvider;
+ _singleControllers = new Dictionary<SingleGraphItem, GraphController>();
+ _multiControllers = new Dictionary<MultiGraphItem, GraphMultiController>();
+ AvailableTechItems = TechItem.GetAvailableTechItems().ToObservableCollection();
+ SelectedTechItem = AvailableTechItems.FirstOrDefault();
+ _diagnoticsDataProperties = typeof(PushDiagnosticsResponse).GetProperties(BindingFlags.Public | BindingFlags.Instance).ToList();
+ ApplicationManager = applicationManager;
+ ApplicationManager.ConnectedMachineChanged += ApplicationManager_ConnectedMachineChanged;
+
+ Adapter = ObservablesEntitiesAdapter.Instance;
+ Elements = new ObservableCollection<IElementEditor>();
+
+ OpenProjectCommand = new RelayCommand(OpenProject);
+ SaveAsProjectCommand = new RelayCommand(SaveAsProject);
+ SaveProjectCommand = new RelayCommand(SaveProject);
+
+ _lastTechProjectFile = SettingsManager.Default.MachineStudio.TechnicianModule.LasTechProjectFile;
+
+ if (File.Exists(_lastTechProjectFile) && loadLastProject)
+ {
+ OpenProjectFile(_lastTechProjectFile);
+ }
+ }
+
+ #endregion
+
+ #region Event Handlers
+
+ /// <summary>
+ /// Applications the manager connected machine changed.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="machine">The machine.</param>
+ private void ApplicationManager_ConnectedMachineChanged(object sender, Integration.Services.IExternalBridgeClient machine)
+ {
+ MachineOperator = machine;
+
+ if (MachineOperator != null)
+ {
+ MachineOperator.DiagnosticsDataAvailable -= MachineOperator_DiagnosticsDataAvailable;
+ MachineOperator.DiagnosticsDataAvailable += MachineOperator_DiagnosticsDataAvailable;
+ }
+ }
+
+ /// <summary>
+ /// Machines the operator diagnostics data available.
+ /// </summary>
+ /// <param name="sender">The sender.</param>
+ /// <param name="response">The response.</param>
+ private void MachineOperator_DiagnosticsDataAvailable(object sender, PushDiagnosticsResponse response)
+ {
+ PopulateDiagnosticsData(response);
+ }
+
+ #endregion
+
+ #region Populate Diagnostics Data
+
+ /// <summary>
+ /// Populates the diagnostics data to the proper elements.
+ /// </summary>
+ /// <param name="data">The data.</param>
+ private void PopulateDiagnosticsData(PushDiagnosticsResponse data)
+ {
+ if (DateTime.Now > _lastDiagnosticsResponseUpdate.AddMilliseconds(MIN_DIAGNOSTICS_UPDATE_MILI))
+ {
+ CurrentDiagnosticsResponse = data;
+ _lastDiagnosticsResponseUpdate = DateTime.Now;
+ CurrentDiagnosticsResponseSize = data.CalculateSize();
+ }
+
+ lock (_elementsLock)
+ {
+ var elements = Elements.ToList();
+
+ foreach (var item in elements.Select(x => x.HostedElement as TechItem))
+ {
+ if (item.GetType() == typeof(MonitorItem))
+ {
+ MonitorItem monitorItem = item as MonitorItem;
+
+ if (DateTime.Now > monitorItem.LastUpdateTime.AddMilliseconds(monitorItem.UpdateInterval))
+ {
+ var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == monitorItem.TechMonitor.Name);
+
+ if (prop != null)
+ {
+ monitorItem.Value = GetDataLastValue(monitorItem.TechMonitor, prop.GetValue(data));
+ }
+ }
+ }
+ else if (item.GetType() == typeof(MeterItem))
+ {
+ MeterItem meterItem = item as MeterItem;
+
+ if (DateTime.Now > meterItem.LastUpdateTime.AddMilliseconds(meterItem.UpdateInterval))
+ {
+ var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == meterItem.TechMonitor.Name);
+
+ if (prop != null)
+ {
+ meterItem.Value = GetDataLastValue(meterItem.TechMonitor, prop.GetValue(data));
+ }
+ }
+ }
+ else if (item.GetType() == typeof(SingleGraphItem))
+ {
+ SingleGraphItem graphItem = item as SingleGraphItem;
+
+ var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == graphItem.TechMonitor.Name);
+
+ if (prop != null)
+ {
+ GraphController controller = null;
+
+ if (_singleControllers.TryGetValue(graphItem, out controller))
+ {
+ controller.PushData(GetDataArray(graphItem.TechMonitor, prop.GetValue(data)));
+ }
+ }
+ }
+ else if (item.GetType() == typeof(MultiGraphItem))
+ {
+ MultiGraphItem graphItem = item as MultiGraphItem;
+
+ var prop = _diagnoticsDataProperties.SingleOrDefault(x => x.Name == graphItem.TechMonitor.Name);
+
+ if (prop != null)
+ {
+ GraphMultiController controller = null;
+
+ if (_multiControllers.TryGetValue(graphItem, out controller))
+ {
+ controller.PushData(GetDataMatrix(graphItem.TechMonitor, prop.GetValue(data)));
+ }
+ }
+ }
+ else if (item.GetType() == typeof(DigitalOutItem))
+ {
+ DigitalOutItem digitalOutItem = item as DigitalOutItem;
+
+ var digitalPin = data.DigitalPins.SingleOrDefault(x => x.Port == digitalOutItem.TechIo.Port);
+
+ if (digitalPin != null)
+ {
+ digitalOutItem.EffectiveValue = digitalPin.Value;
+ }
+ }
+ else if (item.GetType() == typeof(DigitalInItem))
+ {
+ DigitalInItem digitalInItem = item as DigitalInItem;
+
+ var digitalPin = data.DigitalPins.SingleOrDefault(x => x.Port == digitalInItem.TechIo.Port);
+
+ if (digitalPin != null)
+ {
+ digitalInItem.Value = digitalPin.Value;
+ }
+ }
+ }
+ }
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ /// <summary>
+ /// Gets the last data point from a protobuf repeated field.
+ /// </summary>
+ /// <param name="monitor">The monitor.</param>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ private double GetDataLastValue(TechMonitor monitor, object value)
+ {
+ if (!monitor.MultiChannel)
+ {
+ RepeatedField<double> arr = value as RepeatedField<double>;
+ return arr.LastOrDefault();
+ }
+ else
+ {
+ RepeatedField<DoubleArray> arr = value as RepeatedField<DoubleArray>;
+ return arr.Last().Data.Last();
+ }
+ }
+
+ /// <summary>
+ /// Gets the data array from a protobuf repeated field.
+ /// </summary>
+ /// <param name="monitor">The monitor.</param>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ private List<double> GetDataArray(TechMonitor monitor, object value)
+ {
+ return (value as RepeatedField<double>).ToList();
+ }
+
+ /// <summary>
+ /// Gets the data matrix from a protobuf repeated field of <see cref="DoubleArray"/>.
+ /// </summary>
+ /// <param name="monitor">The monitor.</param>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ private List<List<double>> GetDataMatrix(TechMonitor monitor, object value)
+ {
+ DoubleArray[] arrayOfDoubles = Enumerable.ToArray(value as IEnumerable<DoubleArray>);
+ return arrayOfDoubles.Select(x => x.Data.ToList()).ToList();
+ }
+
+ #endregion
+
+ #region Virtual Methods
+
+ /// <summary>
+ /// Called when the disable rendering has been changed
+ /// </summary>
+ protected virtual void OnDisableRenderingChanged()
+ {
+ foreach (var controller in _singleControllers)
+ {
+ controller.Value.ChangeRenderMode(!DisableRendering);
+ }
+
+ foreach (var controller in _multiControllers)
+ {
+ controller.Value.ChangeRenderMode(!DisableRendering);
+ }
+ }
+
+ #endregion
+
+ #region Add/Remove Element
+
+ /// <summary>
+ /// Creates a new tech element by the specified bounds and the current selected element.
+ /// </summary>
+ /// <param name="bounds">The bounds.</param>
+ public void CreateElement(Rect bounds)
+ {
+ CreateElement(SelectedTechItem, bounds);
+ }
+
+ /// <summary>
+ /// Creates a new tech element by the specified tech item instance and bounds.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="bounds">The bounds.</param>
+ private void CreateElement(TechItem item, Rect bounds)
+ {
+ if (item is MonitorItem)
+ {
+ CreateElement<MonitorElementEditor, MonitorItem, TechMonitor>(bounds, Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault());
+ }
+ else if (item is MeterItem)
+ {
+ CreateElement<MeterElementEditor, MeterItem, TechMonitor>(bounds, Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault());
+ }
+ else if (item is SingleGraphItem)
+ {
+ var editor = CreateElement<SingleGraphElementEditor, SingleGraphItem, TechMonitor>(bounds, Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault());
+ InitSingleGraphitem(editor.GraphItem, editor);
+ }
+ else if (item is MultiGraphItem)
+ {
+ var editor = CreateElement<MultiGraphElementEditor, MultiGraphItem, TechMonitor>(bounds, Adapter.TechMonitors.Where(x => x.MultiChannel).FirstOrDefault());
+ InitMultiGraphItem(editor.GraphItem, editor);
+ }
+ else if (item is MotorItem)
+ {
+ var editor = CreateElement<MotorElementEditor, MotorItem, TechMotor>(bounds, Adapter.TechMotors.FirstOrDefault());
+ InitMotorItem(editor.MotorItem);
+ }
+ else if (item is DispenserItem)
+ {
+ var editor = CreateElement<DispenserElementEditor, DispenserItem, TechDispenser>(bounds, Adapter.TechDispensers.FirstOrDefault());
+ InitDispenserItem(editor.DispenserItem);
+ }
+ else if (item is ThreadMotionItem)
+ {
+ var editor = CreateElement<ThreadMotionElementEditor, ThreadMotionItem, object>(bounds, null);
+ InitThreadMotionItem(editor.ThreadMotionItem);
+ }
+ else if (item is MotorGroupItem)
+ {
+ var editor = CreateElement<MotorGroupElementEditor, MotorGroupItem, object>(bounds, null);
+ InitMotorGroupItem(editor.MotorGroupItem);
+ }
+ else if (item is DigitalOutItem)
+ {
+ var editor = CreateElement<DigitalOutElementEditor, DigitalOutItem, TechIo>(bounds, Adapter.TechIos.Where(x => x.Type == IOType.DigitalOutput.ToInt32()).FirstOrDefault());
+ InitDigitalOutItem(editor.DigitalOutItem);
+ }
+ else if (item is DigitalInItem)
+ {
+ CreateElement<DigitalInElementEditor, DigitalInItem, TechIo>(bounds, Adapter.TechIos.Where(x => x.Type == IOType.DigitalInput.ToInt32()).FirstOrDefault());
+ }
+ }
+
+ /// <summary>
+ /// Creates a new element by the specified editor type, tech item type, bounds and tech item constructor value.
+ /// </summary>
+ /// <typeparam name="Editor">The type of the editor.</typeparam>
+ /// <typeparam name="Tech">The type of the tech.</typeparam>
+ /// <typeparam name="Value">The type of the value.</typeparam>
+ /// <param name="bounds">The bounds.</param>
+ /// <param name="value">The value.</param>
+ /// <returns></returns>
+ private Editor CreateElement<Editor, Tech, Value>(Rect bounds, Value value) where Editor : IElementEditor where Tech : TechItem
+ {
+ TechItem item = Activator.CreateInstance(typeof(Tech), new object[] { value }) as TechItem;
+ IElementEditor editor = Activator.CreateInstance(typeof(Editor), new object[] { ((Tech)item), bounds }) as IElementEditor;
+ Elements.Add(editor);
+ return (Editor)editor;
+ }
+
+ /// <summary>
+ /// Creates a new element by the specified editor type and tech item instance.
+ /// </summary>
+ /// <typeparam name="Editor">The type of the editor.</typeparam>
+ /// <param name="item">The item.</param>
+ /// <returns></returns>
+ private Editor CreateElement<Editor>(TechItem item) where Editor : IElementEditor
+ {
+ IElementEditor editor = Activator.CreateInstance(typeof(Editor), new object[] { item, item.GetBounds() }) as IElementEditor;
+ Elements.Add(editor);
+ return (Editor)editor;
+ }
+
+ /// <summary>
+ /// Adds a new tech item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void AddTechItem(TechItem item)
+ {
+ if (item is MonitorItem)
+ {
+ (item as MonitorItem).TechMonitor = Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault(x => x.Guid == item.ItemGuid);
+ CreateElement<MonitorElementEditor>(item);
+ }
+ else if (item is MeterItem)
+ {
+ (item as MeterItem).TechMonitor = Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault(x => x.Guid == item.ItemGuid);
+ CreateElement<MeterElementEditor>(item);
+ }
+ else if (item is SingleGraphItem)
+ {
+ (item as SingleGraphItem).TechMonitor = Adapter.TechMonitors.Where(x => !x.MultiChannel).FirstOrDefault(x => x.Guid == item.ItemGuid);
+ var editor = CreateElement<SingleGraphElementEditor>(item);
+ InitSingleGraphitem(editor.GraphItem, editor);
+ }
+ else if (item is MultiGraphItem)
+ {
+ (item as MultiGraphItem).TechMonitor = Adapter.TechMonitors.Where(x => x.MultiChannel).FirstOrDefault(x => x.Guid == item.ItemGuid);
+ var editor = CreateElement<MultiGraphElementEditor>(item);
+ InitMultiGraphItem(editor.GraphItem, editor);
+ }
+ else if (item is MotorItem)
+ {
+ (item as MotorItem).TechMotor = Adapter.TechMotors.FirstOrDefault(x => x.Guid == item.ItemGuid);
+ var editor = CreateElement<MotorElementEditor>(item);
+ InitMotorItem(editor.MotorItem);
+ }
+ else if (item is DispenserItem)
+ {
+ (item as DispenserItem).TechDispenser = Adapter.TechDispensers.FirstOrDefault(x => x.Guid == item.ItemGuid);
+ var editor = CreateElement<DispenserElementEditor>(item);
+ InitDispenserItem(editor.DispenserItem);
+ }
+ else if (item is ThreadMotionItem)
+ {
+ var editor = CreateElement<ThreadMotionElementEditor>(item);
+ InitThreadMotionItem(editor.ThreadMotionItem);
+ }
+ else if (item is MotorGroupItem)
+ {
+ var editor = CreateElement<MotorGroupElementEditor>(item);
+ InitMotorGroupItem(editor.MotorGroupItem);
+ }
+ else if (item is DigitalOutItem)
+ {
+ (item as DigitalOutItem).TechIo = Adapter.TechIos.FirstOrDefault(x => x.Guid == item.ItemGuid);
+ var editor = CreateElement<DigitalOutElementEditor>(item);
+ InitDigitalOutItem(editor.DigitalOutItem);
+ }
+ else if (item is DigitalInItem)
+ {
+ (item as DigitalInItem).TechIo = Adapter.TechIos.FirstOrDefault(x => x.Guid == item.ItemGuid);
+ CreateElement<DigitalInElementEditor>(item);
+ }
+ }
+
+ /// <summary>
+ /// Called when elements have been removed
+ /// </summary>
+ /// <param name="elements">The elements.</param>
+ public void OnElementsRemoved(List<IElementEditor> elements)
+ {
+ //foreach (var element in elements)
+ //{
+ // if (element.HostedElement is SingleGraphItem)
+ // {
+ // _singleControllers.Remove(element.HostedElement as SingleGraphItem);
+ // (element.HostedElement as SingleGraphItem).Editor.InnerGraph.InnerGraph.Dispose();
+ // }
+ // else if (element.HostedElement is MultiGraphItem)
+ // {
+ // _multiControllers.Remove(element.HostedElement as MultiGraphItem);
+ // (element.HostedElement as MultiGraphItem).Editor.InnerGraph.InnerGraph.Dispose();
+ // }
+ //}
+ }
+
+ /// <summary>
+ /// Called when elements have been pasted
+ /// </summary>
+ /// <param name="elements">The elements.</param>
+ public void OnElementsPasted(List<IElementEditor> elements)
+ {
+ foreach (var element in elements)
+ {
+ if (element is SingleGraphElementEditor)
+ {
+ var graphItem = element.HostedElement as SingleGraphItem;
+ var editor = element as SingleGraphElementEditor;
+ graphItem.Editor = editor;
+ editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame);
+
+ GraphController controller = new GraphController();
+ editor.InnerGraph.Controller = controller;
+
+ _singleControllers.Add(graphItem, controller);
+ }
+ else if (element is MultiGraphElementEditor)
+ {
+ var graphItem = element.HostedElement as MultiGraphItem;
+ var editor = element as MultiGraphElementEditor;
+ editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(graphItem.TechMonitor.PointsPerFrame);
+ graphItem.Editor = editor;
+
+
+ GraphMultiController controller = new GraphMultiController();
+
+ for (int i = 0; i < graphItem.TechMonitor.ChannelCount; i++)
+ {
+ controller.AddSeries(new RealTimeGraphEx.DataSeries.DataYSeries()
+ {
+ UseFillAndStroke = true,
+ Name = graphItem.TechMonitor.Name.First() + (i + 1).ToString(),
+ Stroke = new SolidColorBrush(ColorHelper.GetRandomColor()),
+ });
+ }
+
+ editor.InnerGraph.Controller = controller;
+
+ _multiControllers.Add(graphItem, controller);
+ }
+ else if (element is MotorElementEditor)
+ {
+ var motorItem = element.HostedElement as MotorItem;
+ InitMotorItem(motorItem);
+ }
+ else if (element is DispenserElementEditor)
+ {
+ var dispenser = element.HostedElement as DispenserItem;
+ InitDispenserItem(dispenser);
+ }
+ else if (element is DigitalOutItem)
+ {
+ var ioItem = element.HostedElement as DigitalOutItem;
+ InitDigitalOutItem(ioItem);
+ }
+ else if (element is ThreadMotionItem)
+ {
+ var threadMotionItem = element.HostedElement as ThreadMotionItem;
+ InitThreadMotionItem(threadMotionItem);
+ }
+ else if (element is MotorGroupItem)
+ {
+ var motorGroupItem = element.HostedElement as MotorGroupItem;
+ InitMotorGroupItem(motorGroupItem);
+ }
+ }
+ }
+
+ #endregion
+
+ #region Init Tech Items
+
+ /// <summary>
+ /// Initializes the motor item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void InitMotorItem(MotorItem item)
+ {
+ item.ActionExecuted += async (x, action) =>
+ {
+ if (action == MotorActionType.ForwardPressed)
+ {
+ await MachineOperator.StartMotorJogging(new MotorJoggingRequest()
+ {
+ Code = item.TechMotor.Code,
+ Direction = MotorDirection.Forward,
+ });
+ }
+ else if (action == MotorActionType.ForwardReleased)
+ {
+ await MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest()
+ {
+ Code = item.TechMotor.Code,
+ });
+ }
+ else if (action == MotorActionType.BackwardPressed)
+ {
+ await MachineOperator.StartMotorJogging(new MotorJoggingRequest()
+ {
+ Code = item.TechMotor.Code,
+ Direction = MotorDirection.Backward,
+ });
+ }
+ else if (action == MotorActionType.BackwardReleased)
+ {
+ await MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest()
+ {
+ Code = item.TechMotor.Code,
+ });
+ }
+ else if (action == MotorActionType.HomingStarted)
+ {
+ item.HomingProgress = 0;
+ item.IsHoming = true;
+ item.IsHomingCompleted = false;
+
+ MachineOperator.StartMotorHoming(new MotorHomingRequest()
+ {
+ Code = item.TechMotor.Code
+ })
+ .Subscribe((response) =>
+ {
+
+ item.HomingMaximumProgress = response.Message.MaxProgress;
+ item.HomingProgress = response.Message.Progress;
+
+ }, () =>
+ {
+
+ item.IsHoming = false;
+ item.IsHomingCompleted = true;
+
+ });
+ }
+ else if (action == MotorActionType.HomingStopped)
+ {
+ await MachineOperator.StopMotorHoming(new MotorAbortHomingRequest()
+ {
+ Code = item.TechMotor.Code,
+ });
+
+ item.IsHoming = false;
+ }
+ };
+ }
+
+ /// <summary>
+ /// Initializes the dispenser item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void InitDispenserItem(DispenserItem item)
+ {
+ item.ActionExecuted += async (x, action) =>
+ {
+ if (action == MotorActionType.ForwardPressed)
+ {
+ await MachineOperator.StartDispenserJogging(new DispenserJoggingRequest()
+ {
+ Code = item.TechDispenser.Code,
+ Direction = MotorDirection.Forward,
+ });
+ }
+ else if (action == MotorActionType.ForwardReleased)
+ {
+ await MachineOperator.StopDispenserJogging(new DispenserAbortJoggingRequest()
+ {
+ Code = item.TechDispenser.Code,
+ });
+ }
+ else if (action == MotorActionType.BackwardPressed)
+ {
+ await MachineOperator.StartDispenserJogging(new DispenserJoggingRequest()
+ {
+ Code = item.TechDispenser.Code,
+ Direction = MotorDirection.Backward,
+ });
+ }
+ else if (action == MotorActionType.BackwardReleased)
+ {
+ await MachineOperator.StopDispenserJogging(new DispenserAbortJoggingRequest()
+ {
+ Code = item.TechDispenser.Code,
+ });
+ }
+ else if (action == MotorActionType.HomingStarted)
+ {
+ item.HomingProgress = 0;
+ item.IsHoming = true;
+ item.IsHomingCompleted = false;
+
+ MachineOperator.StartDispenserHoming(new DispenserHomingRequest()
+ {
+ Code = item.TechDispenser.Code
+ })
+ .Subscribe((response) =>
+ {
+
+ item.HomingMaximumProgress = response.Message.MaxProgress;
+ item.HomingProgress = response.Message.Progress;
+
+ }, () =>
+ {
+
+ item.IsHoming = false;
+ item.IsHomingCompleted = true;
+
+ });
+ }
+ else if (action == MotorActionType.HomingStopped)
+ {
+ await MachineOperator.StopDispenserHoming(new DispenserAbortHomingRequest()
+ {
+ Code = item.TechDispenser.Code,
+ });
+
+ item.IsHoming = false;
+ }
+ };
+ }
+
+ /// <summary>
+ /// Initializes the single graph item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="editor">The editor.</param>
+ private void InitSingleGraphitem(SingleGraphItem item, SingleGraphElementEditor editor)
+ {
+ editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(item.TechMonitor.PointsPerFrame);
+ item.Editor = editor;
+
+ GraphController controller = new GraphController();
+ editor.InnerGraph.Controller = controller;
+
+ _singleControllers.Add(item, controller);
+ }
+
+ /// <summary>
+ /// Initializes the multi graph item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <param name="editor">The editor.</param>
+ private void InitMultiGraphItem(MultiGraphItem item, MultiGraphElementEditor editor)
+ {
+ editor.InnerGraph.InnerGraph.MaxPoints = Common.Helpers.GraphsHelper.GetMaxPoints(item.TechMonitor.PointsPerFrame);
+ item.Editor = editor;
+
+ GraphMultiController controller = new GraphMultiController();
+
+ for (int i = 0; i < item.TechMonitor.ChannelCount; i++)
+ {
+ controller.AddSeries(new RealTimeGraphEx.DataSeries.DataYSeries()
+ {
+ UseFillAndStroke = true,
+ Name = item.TechMonitor.Name.First() + (i + 1).ToString(),
+ Stroke = new SolidColorBrush(ColorHelper.GetRandomColor()),
+ });
+ }
+
+ editor.InnerGraph.Controller = controller;
+
+ _multiControllers.Add(item, controller);
+ }
+
+ /// <summary>
+ /// Initializes the thread motion item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void InitThreadMotionItem(ThreadMotionItem item)
+ {
+ item.ActionExecuted += async (x, action) =>
+ {
+ if (action == MotorActionType.ForwardPressed)
+ {
+ await MachineOperator.StartThreadJogging(new ThreadJoggingRequest()
+ {
+ Direction = MotorDirection.Forward,
+ });
+ }
+ else if (action == MotorActionType.BackwardPressed)
+ {
+ await MachineOperator.StartThreadJogging(new ThreadJoggingRequest()
+ {
+ Direction = MotorDirection.Backward,
+ });
+ }
+ else if (action == MotorActionType.ForwardReleased || action == MotorActionType.BackwardReleased)
+ {
+ await MachineOperator.StopThreadJogging(new ThreadAbortJoggingRequest());
+ }
+ };
+ }
+
+ /// <summary>
+ /// Initializes the motor group item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void InitMotorGroupItem(MotorGroupItem item)
+ {
+ item.ActionExecuted += async (x, action) =>
+ {
+ if (action == MotorActionType.ForwardPressed)
+ {
+ await Task.WhenAll(item.TechMotors.Select(motor => MachineOperator.StartMotorJogging(new MotorJoggingRequest()
+ {
+ Code = motor.Code,
+ Direction = MotorDirection.Forward,
+ })));
+ }
+ else if (action == MotorActionType.ForwardReleased)
+ {
+ await Task.WhenAll(item.TechMotors.Select(motor => MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest()
+ {
+ Code = motor.Code,
+ })));
+ }
+ else if (action == MotorActionType.BackwardPressed)
+ {
+ await Task.WhenAll(item.TechMotors.Select(motor => MachineOperator.StartMotorJogging(new MotorJoggingRequest()
+ {
+ Code = motor.Code,
+ Direction = MotorDirection.Backward,
+ })));
+ }
+ else if (action == MotorActionType.BackwardReleased)
+ {
+ await Task.WhenAll(item.TechMotors.Select(motor => MachineOperator.StopMotorJogging(new MotorAbortJoggingRequest()
+ {
+ Code = motor.Code,
+ })));
+ }
+ //else if (action == MotorActionType.HomingStarted)
+ //{
+ // item.HomingProgress = 0;
+ // item.IsHoming = true;
+ // item.IsHomingCompleted = false;
+
+ // MachineOperator.StartMotorHoming(new MotorHomingRequest()
+ // {
+ // Code = item.TechMotor.Code
+ // })
+ // .Subscribe((response) =>
+ // {
+
+ // item.HomingMaximumProgress = response.Message.MaxProgress;
+ // item.HomingProgress = response.Message.Progress;
+
+ // }, () =>
+ // {
+
+ // item.IsHoming = false;
+ // item.IsHomingCompleted = true;
+
+ // });
+ //}
+ //else if (action == MotorActionType.HomingStopped)
+ //{
+ // await MachineOperator.StopMotorHoming(new MotorAbortHomingRequest()
+ // {
+ // Code = item.TechMotor.Code,
+ // });
+
+ // item.IsHoming = false;
+ //}
+ };
+ }
+
+ /// <summary>
+ /// Initializes the digital out item.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ private void InitDigitalOutItem(DigitalOutItem item)
+ {
+ item.ValueChanged += async (x, value) =>
+ {
+ try
+ {
+ await MachineOperator.SetDigitalOut(new SetDigitalOutRequest() { Port = item.TechIo.Port, Value = value });
+ }
+ catch (Exception ex)
+ {
+ //TODO: Show Exception.
+ }
+ };
+ }
+
+ #endregion
+
+ #region Public Methods
+
+ /// <summary>
+ /// Opens a file open dialog to select a project file.
+ /// </summary>
+ public void OpenProject()
+ {
+ OpenFileDialog dlg = new OpenFileDialog();
+ dlg.Title = "Select Technician Project File";
+ dlg.Filter = "Technician Project File|*.tpf";
+
+ if (dlg.ShowDialog().Value)
+ {
+ OpenProjectFile(dlg.FileName);
+ }
+ }
+
+ /// <summary>
+ /// Opens the specified project file path.
+ /// </summary>
+ /// <param name="fileName">File path.</param>
+ public void OpenProjectFile(String fileName)
+ {
+ LoadProject(MachineTechViewProject.Load(fileName));
+ _lastTechProjectFile = fileName;
+ }
+
+ /// <summary>
+ /// Loads the specified project.
+ /// </summary>
+ /// <param name="project">The project.</param>
+ public void LoadProject(MachineTechViewProject project)
+ {
+ using (_notification.PushTaskItem("Loading technician project file..."))
+ {
+ Elements.Clear();
+ _singleControllers.Clear();
+ _multiControllers.Clear();
+
+ foreach (var item in project.Items)
+ {
+ if (item is MotorGroupItem)
+ {
+ (item as MotorGroupItem).TechMotors = ObservablesEntitiesAdapter.Instance.TechMotors.Where(x => (item as MotorGroupItem).ItemsGuids.Contains(x.Guid)).ToObservableCollection();
+ }
+
+ AddTechItem(item);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Opens the file save dialog for selecting a project file target.
+ /// </summary>
+ private void SaveAsProject()
+ {
+ SaveFileDialog dlg = new SaveFileDialog();
+ dlg.Title = "Select Technician Project Location";
+ dlg.Filter = "Technician Project File|*.tpf";
+
+ if (dlg.ShowDialog().Value)
+ {
+ SaveProjectFile(dlg.FileName);
+ }
+ }
+
+ /// <summary>
+ /// Saves the current project to the specified file path.
+ /// </summary>
+ /// <param name="fileName">Name of the file.</param>
+ private void SaveProjectFile(String fileName)
+ {
+ using (_notification.PushTaskItem("Saving technician project file..."))
+ {
+ MachineTechViewProject project = GenerateProjectFile();
+ project.Save(fileName);
+ _lastTechProjectFile = fileName;
+ }
+ }
+
+ /// <summary>
+ /// Saves the current opened project file. If not project file is opened will call <see cref="SaveAsProject"/>.
+ /// </summary>
+ private void SaveProject()
+ {
+ if (File.Exists(_lastTechProjectFile))
+ {
+ SaveProjectFile(_lastTechProjectFile);
+ }
+ else
+ {
+ SaveAsProject();
+ }
+ }
+
+ /// <summary>
+ /// Generates a project file from the current element setup.
+ /// </summary>
+ /// <returns></returns>
+ private MachineTechViewProject GenerateProjectFile()
+ {
+ MachineTechViewProject project = new MachineTechViewProject();
+
+ foreach (var element in Elements)
+ {
+ if (element.HostedElement is MotorGroupItem)
+ {
+ var group = element.HostedElement as MotorGroupItem;
+ group.ItemsGuids = group.TechMotors.Select(x => x.Guid).ToList();
+ }
+
+ (element.HostedElement as TechItem).SetBounds(element.GetBounds());
+ project.Items.Add(element.HostedElement as TechItem);
+ }
+
+ return project;
+ }
+
+ #endregion
+
+ #region IShutdownListener
+
+ /// <summary>
+ /// Called when the application is about to terminate.
+ /// </summary>
+ public void OnShuttingDown()
+ {
+ InvokeUINow(() =>
+ {
+ SettingsManager.Default.MachineStudio.TechnicianModule.LasTechProjectFile = _lastTechProjectFile;
+ });
+ }
+
+ #endregion
+ }
+}