978 lines
39 KiB
C#
978 lines
39 KiB
C#
using System;
|
|
using System.ComponentModel;
|
|
using System.Data;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Media;
|
|
using System.Windows.Threading;
|
|
using LaaPackages.Features.Cordonel.Models;
|
|
using Newtonsoft.Json;
|
|
using NLog;
|
|
using Xylem.Common.CommonCore.Configuration;
|
|
using Xylem.Common.CommonCore.Consts;
|
|
using Xylem.Common.Hardware.Interfaces.Ports.PortCore;
|
|
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses;
|
|
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.Enum;
|
|
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EolProcesses;
|
|
using Xylem.Common.Production.ProductionUiCordonel.ProductionProcesses.EventArgs;
|
|
using Xylem.Common.Utils.Logging;
|
|
using Xylem.Common.Utils.UserAccessCtrl;
|
|
using Control = System.Windows.Forms.Control;
|
|
using TextBox = System.Windows.Controls.TextBox;
|
|
using UserControl = System.Windows.Controls.UserControl;
|
|
|
|
namespace Xylem.Common.Production.ProductionUiCordonel
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for FinalTest.xaml
|
|
/// </summary>
|
|
public sealed partial class ProductionWindow
|
|
{
|
|
#region variables and properties
|
|
private readonly ILogger _logger;
|
|
// remind manually changed culture setting
|
|
private static readonly CultureInfo _cultureInfo = Thread.CurrentThread.CurrentCulture;
|
|
private static readonly AssemblyName _assemblyName = Assembly.GetExecutingAssembly().GetName();
|
|
private static readonly String _assemblyExecRootPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
|
private static readonly Version _version = _assemblyName.Version;
|
|
private readonly String _strSoftwareNameVersion;
|
|
private RegisterLDAPUser _registerForm;
|
|
|
|
private Int32 Slot
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
// maximum processing steps for calculation of progress bar
|
|
private Int32 _maxOverallProcessSteps;
|
|
private Int32 _maxSingleProcessSteps;
|
|
private ProcessController _processCtrl;
|
|
private DateTimeOffset _startTime;
|
|
private DispatcherTimer _timer;
|
|
private String _lastLoggingTextToAvoidRepetition;
|
|
private CordonelRequirements _productionRequirements;
|
|
private UserAccessWindow _userAccessWindow;
|
|
private IProcessStateDef _processStateDef;
|
|
|
|
#endregion
|
|
|
|
public ProductionWindow(String softwareName, String projectName, IProcessStateDef processStateDef)
|
|
{
|
|
_logger = NLogHelper.CreateOrGetLogger(projectName);
|
|
_processStateDef = processStateDef;
|
|
String msg;
|
|
try
|
|
{
|
|
// returns true in DEBUG configuration
|
|
if (!Logic.SoftwareAccessHelper.Access.HasAccess(_assemblyName))
|
|
{
|
|
msg = $"{Properties.Resources.StrStartMessageSwLicenseExpired} {_version}";
|
|
_logger.Error(msg);
|
|
MessageBox.Show(msg, Properties.Resources.StrProcessStateError,
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
Close();
|
|
return;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
msg = Properties.Resources.StrErrorMsgMissingNetworkConnetction + " " + e.Message;
|
|
_logger.Error(msg);
|
|
MessageBox.Show(msg,
|
|
Properties.Resources.StrProcessStateError,
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
InitializeComponent();
|
|
// Log version to files for debug purposes
|
|
_strSoftwareNameVersion = $"{softwareName} {_version}";
|
|
_logger.Info(_strSoftwareNameVersion);
|
|
|
|
Title = _strSoftwareNameVersion;
|
|
|
|
//static labels
|
|
UpdateContentControl(lblSerialNumberTxt, Properties.Resources.StrLblSerialNumberTxt + ":");
|
|
UpdateContentControl(lblRadioAddressText, Properties.Resources.StrLblRadioAddressTxt + ":");
|
|
UpdateContentControl(lblOrderNumberText, Properties.Resources.StrLblOrderNumberTxt + ":");
|
|
UpdateContentControl(lblMeterSizeText, Properties.Resources.StrLblMeterSizeTxt + ":");
|
|
UpdateContentControl(lblSingleProcessText, Properties.Resources.StrLblSingleProcessText + ":");
|
|
UpdateContentControl(lblTotalProcessText, Properties.Resources.StrLblTotalProcessText + ":");
|
|
optionsMenu.Header = Properties.Resources.StrMenuOptionsText;
|
|
optionsMenuChangePassword.Header = Properties.Resources.StrMenuChangePasswordText;
|
|
hlpMenu.Header = Properties.Resources.StrMenuHelpText;
|
|
UpdateUi(lblApprovalText, "");
|
|
UpdateUi(lblTimeText, Properties.Resources.StrLblTimeText + ":");
|
|
|
|
// buttons
|
|
UpdateContentControl(btnStart, Properties.Resources.StrBtnStart);
|
|
UpdateContentControl(btnStop, Properties.Resources.StrBtnStop);
|
|
|
|
InitializeFormState();
|
|
|
|
}
|
|
|
|
private ApplicationSettings Settings
|
|
{
|
|
get; set;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initialize the FinalTest GUI:
|
|
/// - Read the configuration file for slot and port assignments and settings,
|
|
/// - Dispatch slots to slot combobox,
|
|
/// - Read setting from "ProductionUiConfig.json" file for GUI and slot setup,
|
|
/// - Create final process controller and install events,
|
|
/// - Create a dispatch timer to display the elapsed time of the process.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void Window_Initialized(Object sender, EventArgs e)
|
|
{
|
|
var configFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
nameof(Hardware.WaterMeter.Genesis), ProgramConfig.SerialConfigFileName);
|
|
|
|
if (!File.Exists(configFile))
|
|
{
|
|
var msg = Properties.Resources.StrErrorMsgMissingConfigurationFile;
|
|
MessageBox.Show(msg,
|
|
Properties.Resources.StrProcessStateError,
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
_logger.Error(msg);
|
|
throw new ApplicationException(msg);
|
|
}
|
|
var tr = new StreamReader(configFile);
|
|
var meterConfigList = JsonConvert.DeserializeObject<SlotConfig[]>(tr.ReadToEnd());
|
|
|
|
cbxSlotBox.Items.Clear();
|
|
if (meterConfigList != null)
|
|
{
|
|
foreach (var item in meterConfigList.OrderBy(s => s.Slot))
|
|
{
|
|
cbxSlotBox.Items.Add(item.Slot);
|
|
}
|
|
}
|
|
|
|
cbxSlotBox.SelectedIndex = 0;
|
|
Settings = new ApplicationSettings("ProductionUiConfig.json");
|
|
|
|
UseSetting(true);
|
|
|
|
if (cbxSlotBox.SelectedItem == null || string.IsNullOrEmpty(cbxSlotBox.SelectedItem.ToString()) ||
|
|
!int.TryParse(cbxSlotBox.SelectedItem.ToString(), out var slot))
|
|
{
|
|
Slot = 1;
|
|
}
|
|
else
|
|
{
|
|
Slot = slot;
|
|
}
|
|
|
|
try
|
|
{
|
|
_processCtrl = new ProcessController(Slot, _processStateDef);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.Error(ex.Message);
|
|
MessageBox.Show(ex.Message,
|
|
Properties.Resources.StrProcessStateError,
|
|
MessageBoxButton.OK, MessageBoxImage.Error);
|
|
throw new ApplicationException(ex.Message);
|
|
}
|
|
|
|
//install the process changed event handler for single processes
|
|
_processCtrl.OnSingleProcessStateChanged += SingleProcessStateChanged_Handler;
|
|
_processCtrl.OnProcessLogRequest += ProcessLog_Handler;
|
|
_processCtrl.OnProcessProgressChanged += ProcessProgress_Handler;
|
|
_processCtrl.OnOverallProcessStateChanged += ProcessStateChange_Handler;
|
|
|
|
_timer = new DispatcherTimer();
|
|
_timer.Tick += TmrProgressUpdate_Tick;
|
|
_timer.Interval = TimeSpan.FromMilliseconds(500);
|
|
|
|
UpdateStatusGrid();
|
|
}
|
|
|
|
private void Window_Closing(Object sender, CancelEventArgs e)
|
|
{
|
|
_userAccessWindow?.Close();
|
|
_processCtrl.OnSingleProcessStateChanged -= SingleProcessStateChanged_Handler;
|
|
_processCtrl.OnProcessLogRequest -= ProcessLog_Handler;
|
|
_processCtrl.OnProcessProgressChanged -= ProcessProgress_Handler;
|
|
_processCtrl.OnOverallProcessStateChanged -= ProcessStateChange_Handler;
|
|
_userAccessWindow = null;
|
|
|
|
_processCtrl.Dispose();
|
|
_processCtrl = null;
|
|
_timer.Stop();
|
|
_timer.Tick -= TmrProgressUpdate_Tick;
|
|
_timer = null;
|
|
_registerForm = null;
|
|
}
|
|
private void UseSetting(Boolean setSlot = false)
|
|
{
|
|
//tblkAutodetectState.Text = "Off";
|
|
//if (Settings.AutoDetect)
|
|
//{
|
|
// tblkAutodetectState.Text = "On";
|
|
//}
|
|
if (setSlot)
|
|
{
|
|
cbxSlotBox.SelectedValue = Settings.Slot;
|
|
}
|
|
}
|
|
|
|
private void InitializeFormState()
|
|
{
|
|
if (Software.IsRegistrationPending)
|
|
{
|
|
_registerForm = new RegisterLDAPUser();
|
|
_registerForm.OnCancellation += OnUserAccessControlCancellation;
|
|
UiElmEnable(optionsMenu, false, false);
|
|
}
|
|
else
|
|
{
|
|
UiElmEnable(optionsMenu, true);
|
|
UiElmEnable(optionsMenuChangePassword, Software.IsAutenticated);
|
|
UiElmEnable(optionsMenuLogout, Software.IsAutenticated);
|
|
UiElmEnable(optionsMenuLogin, !Software.IsAutenticated);
|
|
UiElmEnable(btnStart, Software.IsAutenticated);
|
|
UiElmEnable(btnStop, false);
|
|
UpdateContentControl(lblOperator,
|
|
Software.IsAutenticated
|
|
? $"{Properties.Resources.StrLblOperatorNameText}: {Software.UserName}"
|
|
: $"{Properties.Resources.StrLblOperatorNameText}: ?");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows the user access window with login form or password change form.
|
|
/// </summary>
|
|
/// <param name="visible"></param>
|
|
/// <param name="control">Windows forms control</param>
|
|
/// <param name="headerTxt"></param>
|
|
/// <remarks date="2025-Mar-25" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void ShowUserAccessWindow(Boolean visible = true, Control control = null, String headerTxt = "")
|
|
{
|
|
if (visible && control != null)
|
|
{
|
|
UiElmEnable(optionsMenu, false);
|
|
|
|
if (_userAccessWindow == null)
|
|
_userAccessWindow = new UserAccessWindow(control, headerTxt);
|
|
// View the user access window as container for the windows forms password change and login
|
|
_userAccessWindow.OnCloseWindow += OnUserAccessWindowClosed_Handler;
|
|
_userAccessWindow.ShowDialog();
|
|
}
|
|
else
|
|
{
|
|
if (_userAccessWindow != null)
|
|
{
|
|
_userAccessWindow.OnCloseWindow -= OnUserAccessWindowClosed_Handler;
|
|
try
|
|
{
|
|
_userAccessWindow.Close();
|
|
}
|
|
catch (Exception)
|
|
{
|
|
//ignore
|
|
}
|
|
_userAccessWindow = null;
|
|
}
|
|
|
|
if (_registerForm != null)
|
|
_registerForm.OnCancellation -= OnUserAccessControlCancellation;
|
|
|
|
UiElmEnable(optionsMenu, true);
|
|
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Close event handler of the user access window with login form or password change form.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="eventArgs"></param>
|
|
/// <remarks date="2025-Mar-25" author="Thomas Wiedebusch">
|
|
/// - Initial.
|
|
/// </remarks>
|
|
private void OnUserAccessWindowClosed_Handler(Object sender, EventArgs eventArgs)
|
|
{
|
|
ShowUserAccessWindow(false);
|
|
InitializeFormState();
|
|
}
|
|
|
|
private void UpdateUi(ContentControl c, String content, Brush color = null)
|
|
{
|
|
if (color == null)
|
|
color = Brushes.Black;
|
|
|
|
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
c.Content = content;
|
|
c.Foreground = color;
|
|
}));
|
|
}
|
|
|
|
private void UpdateUi(TextBox c, String content, Brush color = null)
|
|
{
|
|
if (color == null)
|
|
color = Brushes.Black;
|
|
|
|
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
c.Text = content;
|
|
c.Foreground = color;
|
|
}));
|
|
}
|
|
private void UpdateUi(TextBlock c, String content, Brush color = null)
|
|
{
|
|
if (color == null)
|
|
color = Brushes.Black;
|
|
|
|
c.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
c.Text = content;
|
|
c.Foreground = color;
|
|
}));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the elapsed time as information
|
|
/// </summary>
|
|
/// <returns>information attached to process depending on region</returns>
|
|
/// <remarks date="2024-Jul-11" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void SetTimeDisplay()
|
|
{
|
|
var time = DateTimeOffset.UtcNow;
|
|
var timeSpan = time - _startTime;
|
|
UpdateContentControl(lblTimeValue, $@"{(UInt32)timeSpan.TotalMinutes}:{timeSpan.Seconds:00}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Common routine for state change:
|
|
/// - Log state change,
|
|
/// - Execute stop procedure on error.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="2020-Dec-12" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-Aug-30" author="Thomas Wiedebusch">
|
|
/// - Extended.
|
|
/// </remarks>
|
|
/// <remarks date="2025-Apr-10" author="Thomas Wiedebusch">
|
|
/// - Extended.
|
|
/// </remarks>
|
|
private void ProcessStateChange_Handler(Object sender, ProcessStateArgs e)
|
|
{
|
|
_logger.Debug($"Slot:{Slot} - Final test state: {e.State}");
|
|
|
|
// Nothing to display
|
|
if (e.State == ProcessState.Idle)
|
|
{
|
|
// Update progress bars
|
|
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
|
ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps));
|
|
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
|
ProcessProgressArgs.ProcessProgressType.ActualProcessSteps));
|
|
}
|
|
// Stop all procedures
|
|
if (e.State == ProcessState.Stop)
|
|
{
|
|
_timer?.Stop();
|
|
UiElmEnable(btnStart, true);
|
|
UiElmEnable(btnStop, false);
|
|
// update progress bars
|
|
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
|
ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps));
|
|
ProcessProgress_Handler(this, new ProcessProgressArgs(0,
|
|
ProcessProgressArgs.ProcessProgressType.ActualProcessSteps));
|
|
// remove user control
|
|
SetNewUserControl(null);
|
|
}
|
|
// Repeat failed tests
|
|
if (e.State == ProcessState.RepeatFailedTests)
|
|
{
|
|
UiElmEnable(btnStart, false);
|
|
UiElmEnable(btnStop, true);
|
|
_timer?.Start();
|
|
}
|
|
// Stop time for manual operation and visual inspection as this is not part of the configuration
|
|
if (e.State == ProcessState.CheckOrderNumber)
|
|
{
|
|
_timer?.Stop();
|
|
}
|
|
// Prepare shipping
|
|
if (e.State == ProcessState.PrepareShippingMode)
|
|
{
|
|
_timer?.Stop();
|
|
UiElmEnable(btnStart, false);
|
|
UiElmEnable(btnStop, false);
|
|
}
|
|
// Ready for shipping
|
|
if (e.State == ProcessState.ReadyForShipping)
|
|
{
|
|
// Create extended report including all steps and each register write, read and comparison
|
|
CreateFile(Properties.Resources.StrInfoSuccessPapers);
|
|
BtnStop_Click(this, null);
|
|
}
|
|
// Print return report
|
|
if (e.State == ProcessState.PrintReturnReport)
|
|
{
|
|
PrintErrorNote();
|
|
BtnStop_Click(this, null);
|
|
}
|
|
// Print success report
|
|
if (e.State == ProcessState.PrintSuccessReport)
|
|
{
|
|
PrintSuccessNote();
|
|
BtnStop_Click(this, null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Enable UI elements
|
|
/// </summary>
|
|
/// <param name="elm"></param>
|
|
/// <param name="isEnabled"></param>
|
|
/// <param name="isVisible"></param>
|
|
private void UiElmEnable(UIElement elm, Boolean isEnabled, Boolean isVisible = true)
|
|
{
|
|
elm.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
elm.Visibility = isVisible ? Visibility.Visible : Visibility.Hidden;
|
|
elm.IsEnabled = isEnabled;
|
|
|
|
}));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fill logging window with information
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="????" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2023-07-06" author="Thomas Wiedebusch">
|
|
/// - Changed to rich text edit with colored output.
|
|
/// </remarks>
|
|
/// <remarks date="2024-08-28" author="Thomas Wiedebusch">
|
|
/// - Avoid output of repeated text or useless empty text.
|
|
/// </remarks>
|
|
private void ProcessLog_Handler(Object sender, ProcessLogArgs e)
|
|
{
|
|
rtbLog.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
if (e != null)
|
|
{
|
|
try
|
|
{
|
|
// remove unacceptable spacing between the lines
|
|
rtbLog.Document.LineHeight = 1;
|
|
|
|
var color = e.Color ?? Brushes.Black;
|
|
var text = e.Data;
|
|
if (!string.IsNullOrEmpty(text) && !text.Equals(_lastLoggingTextToAvoidRepetition))
|
|
{
|
|
var tr = new TextRange(rtbLog.Document.ContentEnd, rtbLog.Document.ContentEnd)
|
|
{
|
|
Text = text
|
|
};
|
|
tr.ApplyPropertyValue(TextElement.ForegroundProperty, color);
|
|
rtbLog.ScrollToEnd();
|
|
rtbLog.AppendText(Environment.NewLine);
|
|
}
|
|
|
|
_lastLoggingTextToAvoidRepetition = text;
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set values for progress bar, maximum and actual for single process and overall process.
|
|
/// - Limit values to 0.0..100.0.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="????" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-07-18" author="Thomas Wiedebusch">
|
|
/// - Introduced multi line text with center alignment.
|
|
/// </remarks>
|
|
private void ProcessProgress_Handler(Object sender, ProcessProgressArgs e)
|
|
{
|
|
if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.MaxOverallProcessSteps)
|
|
{
|
|
_maxOverallProcessSteps = e.Progress;
|
|
}
|
|
else if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.MaxActualProcessSteps)
|
|
{
|
|
_maxSingleProcessSteps = e.Progress;
|
|
}
|
|
if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.OverallProcessesSteps)
|
|
{
|
|
pbTotalProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
// limit output to progress bar to 0..100 as integer for process bar
|
|
var progress = _maxOverallProcessSteps <= 0 ? 0.0 : e.Progress * 100.0 / _maxOverallProcessSteps;
|
|
progress = progress > 100.0 ? 100.0 : progress < 0.0 ? 0.0 : progress;
|
|
pbTotalProgress.Value = (Int32)progress;
|
|
UpdateContentControl(lblTotalProgressValue, $@"{progress:##0.0} %");
|
|
}
|
|
));
|
|
}
|
|
else if (e.ProgressType == ProcessProgressArgs.ProcessProgressType.ActualProcessSteps)
|
|
{
|
|
pbSubProgress.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
// limit output to progress bar to 0..100 as integer for process bar
|
|
var progress = _maxSingleProcessSteps <= 0 ? 0.0 : e.Progress * 100.0 / _maxSingleProcessSteps;
|
|
progress = progress > 100.0 ? 100.0 : progress < 0.0 ? 0.0 : progress;
|
|
pbSubProgress.Value = (Int32)progress;
|
|
UpdateContentControl(lblSubProgressValue, $@"{progress:##0.0} %");
|
|
}
|
|
));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Output message to control without access violation.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="????" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2023-07-11" author="Thomas Wiedebusch">
|
|
/// - Introduced multi line text with center alignment.
|
|
/// </remarks>
|
|
private static void UpdateContentControl(ContentControl ctl, String text)
|
|
{
|
|
ctl.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
ctl.Content = new TextBlock()
|
|
{
|
|
Text = text,
|
|
TextWrapping = TextWrapping.Wrap,
|
|
TextAlignment = TextAlignment.Center
|
|
};
|
|
}
|
|
));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Status grid update for all single processes
|
|
/// </summary>
|
|
private void UpdateStatusGrid()
|
|
{
|
|
var dt = new DataTable();
|
|
dt.Columns.Add(Properties.Resources.StrDataTableColumnProcess);
|
|
dt.Columns.Add(Properties.Resources.StrDataTableColumnState);
|
|
var i = 0;
|
|
if (_processCtrl?.Processes == null)
|
|
return;
|
|
foreach (var item in _processCtrl.Processes)
|
|
{
|
|
dt.Rows.Add();
|
|
dt.Rows[i][0] = item.ProcessName;
|
|
dt.Rows[i][1] = ProductionProcessStateHelper.GetTextFromProductionProcessState(item.SingleProcessState);
|
|
i++;
|
|
}
|
|
|
|
dgTotalProcess.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
dgTotalProcess.DataContext = dt;
|
|
}
|
|
));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dispatch new user control to main screen
|
|
/// </summary>
|
|
/// <param name="uc"></param>
|
|
private void SetNewUserControl(UserControl uc)
|
|
{
|
|
dgTotalProcess.Dispatcher.Invoke(DispatcherPriority.Normal,
|
|
new Action(() =>
|
|
{
|
|
// remove last userControl
|
|
dpSubProcess.Children.Clear();
|
|
if (uc != null)
|
|
{
|
|
dpSubProcess.Children.Add(uc);
|
|
DockPanel.SetDock(uc, Dock.Top); // & Dock.Left);
|
|
}
|
|
}
|
|
));
|
|
}
|
|
|
|
#region TimerControls
|
|
/// <summary>
|
|
/// Handle timing depending updates.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
/// <remarks date="2024-07-11" author="Thomas Wiedebusch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
private void TmrProgressUpdate_Tick(Object sender, EventArgs e)
|
|
{
|
|
SetTimeDisplay();
|
|
}
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Update of status grid with information returned by user control.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
/// <remarks date="????" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-08-28" author="Thomas Wiedebusch">
|
|
/// - Activate new user control on start of process.
|
|
/// </remarks>
|
|
private void SingleProcessStateChanged_Handler(Object sender, SingleProcessStateArgs e)
|
|
{
|
|
if (sender is IProductionProcess productionProcess)
|
|
{
|
|
if (e.SingleProcessState == SingleProcessState.Running)
|
|
{
|
|
// Set new user control
|
|
SetNewUserControl(productionProcess.GetUserControl());
|
|
}
|
|
else
|
|
{
|
|
// remove user control on idle, skipped, abort or error
|
|
SetNewUserControl(null);
|
|
}
|
|
}
|
|
|
|
UpdateStatusGrid();
|
|
UpdateGuiWithProductInfos();
|
|
}
|
|
|
|
private void OnUserAccessControlCancellation(Control control)
|
|
{
|
|
OnUserAccessWindowClosed_Handler(this, null);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Set labels of device information and order number
|
|
/// </summary>
|
|
/// <remarks date="????" author="Roland Drabesch">
|
|
/// - Initial
|
|
/// </remarks>
|
|
/// <remarks date="2024-07-15" author="Thomas Wiedebusch">
|
|
/// - Additional info of Cordonel.
|
|
/// </remarks>
|
|
private void UpdateGuiWithProductInfos()
|
|
{
|
|
var genesisMeter = _processCtrl?.GetGenesisMeter();
|
|
_productionRequirements = _processCtrl?.GetProductionRequirements();
|
|
|
|
if (genesisMeter == null)
|
|
return;
|
|
|
|
UpdateContentControl(lblOrderNumberValue,
|
|
genesisMeter.OrderNumber != 0 ? genesisMeter.OrderNumber.ToString() : "?");
|
|
|
|
UpdateContentControl(lblRadioAddressValue,
|
|
genesisMeter.RadioAddress != 0 ? genesisMeter.RadioAddress.ToString() : "");
|
|
UpdateContentControl(lblRadioAddressText,
|
|
genesisMeter.RadioAddress != 0 ? Properties.Resources.StrLblRadioAddressTxt + ":" : "");
|
|
|
|
UpdateContentControl(lblFwValue,
|
|
!string.IsNullOrEmpty(genesisMeter.FwVersion) ? genesisMeter.FwVersion : "?");
|
|
|
|
UpdateContentControl(lblMeterSizeValue,
|
|
!string.IsNullOrEmpty(genesisMeter.MeterSize) ? genesisMeter.MeterSize : "?");
|
|
|
|
UpdateContentControl(lblLutValue,
|
|
!string.IsNullOrEmpty(genesisMeter.LutCrc) ? genesisMeter.LutCrc : "?");
|
|
|
|
|
|
UpdateContentControl(lblSerialNumberValue,
|
|
!string.IsNullOrEmpty(genesisMeter.CustomerSerialNumber) ? genesisMeter.CustomerSerialNumber : "?");
|
|
|
|
UpdateContentControl(lblRegionValue,
|
|
!string.IsNullOrEmpty(genesisMeter.Region) ? genesisMeter.Region : "?");
|
|
|
|
UpdateUi(lblPcbIdValue, !string.IsNullOrEmpty(genesisMeter.PcbId) ? genesisMeter.PcbId : "?");
|
|
|
|
var msg = "";
|
|
var color = Brushes.Black;
|
|
if (_productionRequirements?.IsSpecialActive != null && (Boolean)_productionRequirements.IsSpecialActive &&
|
|
_productionRequirements?.IsSpecialApproved != null && (Boolean)_productionRequirements.IsSpecialApproved)
|
|
{
|
|
msg = $"{Properties.Resources.StrLblSpecialRequirement} - Id.Ver: {_productionRequirements.SpecialId}." +
|
|
$"{_productionRequirements.SpecialVersion}";
|
|
color = Brushes.Red;
|
|
}
|
|
else if (_productionRequirements?.IsStandardActive != null && (Boolean)_productionRequirements.IsStandardActive &&
|
|
_productionRequirements?.IsStandardApproved != null && (Boolean)_productionRequirements.IsStandardApproved)
|
|
{
|
|
msg = $"{Properties.Resources.StrLblStandardRequirement} - Id.Ver: {_productionRequirements.StandardId}." +
|
|
$"{_productionRequirements.StandardVersion}";
|
|
}
|
|
|
|
UpdateUi(lblApprovalText, msg, color);
|
|
}
|
|
|
|
//private void BtnSwitchAutoDetect_Click(Object sender, RoutedEventArgs e)
|
|
//{
|
|
// //Settings.AutoDetect = !Settings.AutoDetect;
|
|
// //StoreSetting();
|
|
// //UseSetting();
|
|
//}
|
|
|
|
private void OnLogout_Click(Object sender, EventArgs e)
|
|
{
|
|
Software.Logout();
|
|
InitializeFormState();
|
|
}
|
|
|
|
private void OnLogin_Click(Object sender, EventArgs args)
|
|
{
|
|
ShowUserAccessWindow(true, new LoginForm(OnUserAccessControlCancellation),
|
|
Properties.Resources.StrLoginMsg);
|
|
}
|
|
|
|
private void OnChangePassword_Click(Object _, EventArgs _1)
|
|
{
|
|
ShowUserAccessWindow(true, new ChangePassword(OnUserAccessControlCancellation),
|
|
Properties.Resources.StrChangePasswordMsg);
|
|
}
|
|
|
|
private void CbxSlotBox_SelectionChanged(Object sender, SelectionChangedEventArgs e)
|
|
{
|
|
|
|
}
|
|
|
|
private void StoreSetting()
|
|
{
|
|
Settings.Update("ProductionUiConfig.json");
|
|
}
|
|
|
|
//private void BtnConnect_Click(Object sender, RoutedEventArgs e)
|
|
//{
|
|
// Settings.Slot = (Int32)cbxSlotBox.SelectedValue;
|
|
// StoreSetting();
|
|
//}
|
|
|
|
private void BtnStart_Click(Object sender, RoutedEventArgs e)
|
|
{
|
|
UiElmEnable(btnStart, false);
|
|
UiElmEnable(btnStop, true);
|
|
|
|
_startTime = DateTimeOffset.UtcNow;
|
|
_timer?.Start();
|
|
|
|
// remove last userControl
|
|
dpSubProcess.Children.Clear();
|
|
rtbLog.Document.Blocks.Clear();
|
|
|
|
// clear all visual fields as it may be a new pcbId
|
|
UpdateContentControl(lblOrderNumberValue, "?");
|
|
UpdateContentControl(lblRadioAddressValue, "");
|
|
UpdateContentControl(lblRadioAddressText, "");
|
|
UpdateContentControl(lblFwValue, "?");
|
|
UpdateContentControl(lblMeterSizeValue, "?");
|
|
UpdateContentControl(lblLutValue, "?");
|
|
UpdateContentControl(lblSerialNumberValue, "?");
|
|
UpdateContentControl(lblRegionValue, "?");
|
|
UpdateUi(lblPcbIdValue, "?");
|
|
|
|
_processCtrl?.SetProcessState(ProcessState.DetectCordonel);
|
|
}
|
|
|
|
private void PrintErrorNote()
|
|
{
|
|
// Safe report to file
|
|
CreateFile(Properties.Resources.StrInstructionReturnPapers, true, true);
|
|
}
|
|
|
|
private void PrintSuccessNote()
|
|
{
|
|
// Safe report to file
|
|
CreateFile(Properties.Resources.StrInfoSuccessPapers, true, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Logging a file with all process information, building a compressed report for printout.
|
|
/// </summary>
|
|
/// <remarks date="2025-Apr-10" author="Thomas Wiedebusch">
|
|
/// - Reduced printout.
|
|
/// </remarks>
|
|
private void CreateFile(String headerInfo, Boolean shortReport = false, Boolean printReport = false)
|
|
{
|
|
var sb = new StringBuilder();
|
|
var genesisMeter = _processCtrl.GetGenesisMeter();
|
|
|
|
sb.AppendLine("========================================================================");
|
|
sb.AppendLine(headerInfo);
|
|
sb.AppendLine("========================================================================");
|
|
sb.AppendLine(_strSoftwareNameVersion);
|
|
sb.AppendLine("------------------------------------------------------------------------");
|
|
sb.AppendLine($"{Properties.Resources.StrDateTime}: {DateTime.Now}");
|
|
sb.AppendLine("------------------------------------------------------------------------");
|
|
sb.AppendLine($"PcbId: {genesisMeter.PcbId}");
|
|
sb.AppendLine($"{Properties.Resources.StrPrintOrderNumberTxt}: {genesisMeter.OrderNumber}");
|
|
sb.AppendLine($"{Properties.Resources.StrLblSerialNumberTxt}: {genesisMeter.CustomerSerialNumber}");
|
|
sb.AppendLine($"{Properties.Resources.StrLblOperatorNameText}: {Software.UserName}");
|
|
sb.AppendLine("------------------------------------------------------------------------");
|
|
|
|
//TODO THW take the log path from setup (done with GTB)
|
|
var loggingPath = $"C:\\GenesisLog\\{DateTime.Now:yyyy-MM-dd}\\ProductionUiCordonel\\";
|
|
var fileName = $"{loggingPath}{DateTime.Now.ToString("yyyyMMddHHmmss")}_ExtendedReport_{genesisMeter.PcbId}.txt";
|
|
|
|
// Copy the header to the compressed string builder
|
|
var compressedSb = new StringBuilder();
|
|
if (shortReport)
|
|
{
|
|
compressedSb.Append(sb);
|
|
}
|
|
|
|
var rtbText = new TextRange(
|
|
rtbLog.Document.ContentStart,
|
|
rtbLog.Document.ContentEnd
|
|
);
|
|
sb.Append($"{rtbText.Text}");
|
|
// Write the complete report to the file
|
|
File.WriteAllText(fileName, sb.ToString());
|
|
|
|
// Reduce sb content to compress it for printout
|
|
if (shortReport)
|
|
{
|
|
|
|
fileName = $"{loggingPath}{DateTime.Now.ToString("yyyyMMddHHmmss")}" +
|
|
$"_ShortReport_{genesisMeter.PcbId}.txt";
|
|
var sr = new StringReader(rtbText.Text);
|
|
var srLine = sr.ReadLine();
|
|
while (srLine != null)
|
|
{
|
|
if (srLine.Contains(Properties.Resources.StrProcessStateError) ||
|
|
srLine.Contains(Properties.Resources.StrProcessStateDone) ||
|
|
srLine.Contains(Properties.Resources.StrProcessStateWarning) ||
|
|
srLine.Contains(Properties.Resources.StrProcessStateSkipped) ||
|
|
srLine.Contains(Properties.Resources.StrWarningMsgSpecialRequirementActive))
|
|
compressedSb.AppendLine(srLine);
|
|
srLine = sr.ReadLine();
|
|
}
|
|
|
|
// Returns the compressed file for error report printout
|
|
File.WriteAllText(fileName, compressedSb.ToString());
|
|
if (printReport)
|
|
{
|
|
Process.Start(fileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stop button as user interaction to kill the finalization process
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void BtnStop_Click(Object sender, RoutedEventArgs e)
|
|
{
|
|
//set the process state to the state machine
|
|
_processCtrl?.SetProcessState(ProcessState.Stop);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Open requirement in Web-Browser.
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="e"></param>
|
|
private void LblApprovalText_Click(Object sender, System.Windows.Input.MouseButtonEventArgs e)
|
|
{
|
|
var requirementId = 0;
|
|
var requirementWebPageLink = ServiceUrls.InspectCordonelRequirementInfoServiceUrl();
|
|
if (_productionRequirements?.SpecialId != null &&
|
|
_productionRequirements?.IsSpecialApproved != null &&
|
|
_productionRequirements.SpecialId != 0)
|
|
{
|
|
requirementId = (Int32)_productionRequirements.SpecialId;
|
|
requirementWebPageLink += $"SpecialRequirements#{requirementId}";
|
|
}
|
|
else if (_productionRequirements?.StandardId != null &&
|
|
_productionRequirements?.IsStandardApproved != null &&
|
|
_productionRequirements.StandardId != 0)
|
|
{
|
|
requirementId = (Int32)_productionRequirements.StandardId;
|
|
requirementWebPageLink += $"StandardRequirements#{requirementId}";
|
|
}
|
|
|
|
if (requirementId != 0)
|
|
{
|
|
Process.Start(requirementWebPageLink);
|
|
}
|
|
}
|
|
|
|
private void HlpMenu_Click(Object sender, RoutedEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
var filename = "";
|
|
if (Thread.CurrentThread.CurrentCulture.Name.Contains("de"))
|
|
{
|
|
filename = Path.Combine(_assemblyExecRootPath, "Docu", @"Handbuch Cordonel Versandfertigmachen (VFM).pdf");
|
|
}
|
|
else if (Thread.CurrentThread.CurrentCulture.Name.Contains("en"))
|
|
{
|
|
filename = Path.Combine(_assemblyExecRootPath, "Docu", @"Manual Cordonel End of Line Test (EOL).pdf");
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(filename))
|
|
{
|
|
Process.Start(filename);
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Console.WriteLine(exception);
|
|
}
|
|
}
|
|
|
|
private void Window_Loaded(Object sender, RoutedEventArgs e)
|
|
{
|
|
if (!Software.IsAutenticated)
|
|
OnLogin_Click(this, null);
|
|
|
|
}
|
|
}
|
|
}
|