Witam.
Potrzebuje nakierowania lekkiego, bo już 3 dni z tym walczę. Miałem wątek na forum o tym, że chciałem słuchać wag w .NET Core ale na szczęście ten pomysł przepadł. Wydawało mi się, że WinForms sobie z tym poradzi zdecydowanie lepiej, ale jednak nie.
Do systemu dopisuje sobie wagi. U tego klienta są dwie - pierwsza na COM2, druga na COM3. Czego potrzebuje:
- Dwa miejsca ważenia -> 1. Szybkie ważenie - pokazuje wagę, 2. Wydawanie - ważenie podczas kompletowania towaru (wydawania)
- Każde z tych miejsc ma możliwość przełączania wag. Do tego jest guzik "Zmień wagę"
Gdzie zmiana wagi nie robi dużego problemu w obrębie jednej funkcji, tak przełączenie się na pomiędzy Szybkim ważeniem, a Wydawaniem generuje kompletny chaos.
SYSTEM
Jedno główne okno MainForm
, który zawiera panel i ten panel przyjmuje odpowiednie usercontrol - ucPacking
lub ucWeighting
.
Stworzyłem statyczną klasę, w której trzymam obiekt SerialPort
public static class SerialPortService
{
public static SafeSerialPort SerialPort;
private static Logger _logger;
public static void CreateConnection(Scale s, Logger logger)
{
_logger = logger;
if(SerialPort != null && SerialPort.IsOpen)
{
SerialPort.DiscardInBuffer();
SerialPort.DiscardOutBuffer();
SerialPort.Close();
}
SerialPort = new SafeSerialPort(s);
SerialPort.Handshake = Handshake.None;
}
public static void ChangeScale(Scale s)
{
if (SerialPort != null && SerialPort.IsOpen)
{
if(SerialPort.IsOpen)
{
SerialPort.DiscardInBuffer();
SerialPort.DiscardOutBuffer();
SerialPort.Close();
SerialPort = new SafeSerialPort(s);
SerialPort.Handshake = Handshake.None;
}
else
{
SerialPort = new SafeSerialPort(s);
SerialPort.Handshake = Handshake.None;
}
}
}
}
Stworzyłem również klasę poprawiającą nieco Close()
, ponieważ, .NET czegoś tam nie zwalnia domyślnie.
public class SafeSerialPort : SerialPort
{
private Stream theBaseStream;
private Scale _scale;
public SafeSerialPort(Scale scale)
: base(scale.PortName, scale.BaundRate, scale.Parity, scale.DataBits, scale.StopBits)
{
_scale = scale;
}
public new void Open()
{
try
{
base.Open();
theBaseStream = BaseStream;
GC.SuppressFinalize(theBaseStream);
}
catch
{
}
}
public new void Dispose()
{
Dispose(true);
}
protected override void Dispose(bool disposing)
{
if (disposing && (base.Container != null))
{
base.Container.Dispose();
}
try
{
if (theBaseStream.CanRead)
{
theBaseStream.Close();
GC.ReRegisterForFinalize(theBaseStream);
}
}
catch
{
// ignore exception - bug with USB - serial adapters.
}
base.Dispose(disposing);
}
}
Obie funkcje systemu mają taką samą implementacje połączenia i pobierania danych z wagi, więc wrzucę tylko raz
private Scale _selectedScale;
private object locker = new object();
private delegate void SerialPortDelegate(string data);
private SerialPortDelegate _delegate;
private void ucWeighting_Load(object sender, EventArgs e)
{
_delegate = new SerialPortDelegate(ReadSerialPort);
if (_settings.Scales.Count > 0)
{
_selectedScale = _settings.Scales[0];
lbTitleScale.Text = "PROSTE WAŻENIE [" + _selectedScale.Name + "]";
SerialPortService.CreateConnection(_selectedScale, _logger);
SerialPortService.SerialPort.Open();
SerialPortService.SerialPort.DataReceived += _serialPort_DataReceived;
}
}
private async void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
await Task.Delay(500);
if (!tbWeight.IsDisposed)
{
if (tbWeight.InvokeRequired)
{
string data = SerialPortService.SerialPort.ReadLine();
tbWeight.Invoke(_delegate, new object[] { data });
}
}
}
private void btnChangeScale_Click(object sender, EventArgs e)
{
try
{
_tara = new List<decimal>();
int index = _settings.Scales.IndexOf(_selectedScale) + 1;
if (index <= _settings.Scales.Count - 1)
{
_selectedScale = _settings.Scales[index];
}
else
{
_selectedScale = _settings.Scales[0];
}
lbTitleScale.Text = "PROSTE WAŻENIE [" + _selectedScale.Name + "]";
SerialPortService.ChangeScale(_selectedScale);
SerialPortService.SerialPort.Open();
SerialPortService.SerialPort.DataReceived += _serialPort_DataReceived;
}
catch (Exception ex)
{
_scaleError = ex.Message;
_logger.Error(ex, "[ucWeighting] WAGA");
tbWeight.Text = "ERROR";
}
}
BŁĘDY
Informacje o wyjątku: System.ArgumentOutOfRangeException
w System.Text.DecoderNLS.GetCharCount(Byte[], Int32, Int32, Boolean)
w System.Text.DecoderNLS.GetCharCount(Byte[], Int32, Int32)
w System.IO.Ports.SerialPort.InternalRead(Char[], Int32, Int32, Int32, Boolean)
w System.IO.Ports.SerialPort.ReadTo(System.String)
w System.IO.Ports.SerialPort.ReadLine()
w RanchoApp.Forms.ucPacking+<_serialPort_DataReceived>d__21.MoveNext()
w System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_1(System.Object)
w System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
w System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
w System.Threading.ThreadPoolWorkQueue.Dispatch()
w System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Informacje o wyjątku: System.OverflowException
w System.IO.Ports.SerialPort.ReadTo(System.String)
w System.IO.Ports.SerialPort.ReadLine()
w RanchoApp.Forms.ucWeighting+<_serialPort_DataReceived>d__13.MoveNext()
w System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_1(System.Object)
w System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
w System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
w System.Threading.ThreadPoolWorkQueue.Dispatch()
w System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Informacje o wyjątku: System.ObjectDisposedException
w System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
w System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
w RanchoApp.Forms.ucWeighting._serialPort_DataReceived(System.Object, System.IO.Ports.SerialDataReceivedEventArgs)
w System.IO.Ports.SerialPort.CatchReceivedEvents(System.Object, System.IO.Ports.SerialDataReceivedEventArgs)
w System.IO.Ports.SerialStream+EventLoopRunner.CallReceiveEvents(System.Object)
w System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
w System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
w System.Threading.ThreadPoolWorkQueue.Dispatch()
w System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Informacje o wyjątku: System.IO.IOException
w System.IO.Ports.InternalResources.WinIOError(Int32, System.String)
w System.IO.Ports.SerialStream.EndRead(System.IAsyncResult)
w System.IO.Ports.SerialStream.Read(Byte[], Int32, Int32, Int32)
w System.IO.Ports.SerialStream.Read(Byte[], Int32, Int32)
w System.IO.Ports.SerialPort.InternalRead(Char[], Int32, Int32, Int32, Boolean)
w System.IO.Ports.SerialPort.ReadTo(System.String)
w System.IO.Ports.SerialPort.ReadLine()
w RanchoApp.Forms.ucPacking._serialPort_DataReceived(System.Object, System.IO.Ports.SerialDataReceivedEventArgs)
w System.IO.Ports.SerialPort.CatchReceivedEvents(System.Object, System.IO.Ports.SerialDataReceivedEventArgs)
w System.IO.Ports.SerialStream+EventLoopRunner.CallReceiveEvents(System.Object)
w System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(System.Object)
w System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
w System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
w System.Threading.ThreadPoolWorkQueue.Dispatch()
w System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
Co ja jeszcze mogę zrobić żeby to działało stabilnie?