Below is the code for a class I have that handles connection and interaction with a serial device. I call the connect function from another class as is shown immediately below this as well. My question is: what is the best way to update my progress bar, which is located on a different class than the one where I initialize the background worker? I am having issues, because I am trying to update something that is across threads and across classes. Passing the form class into my connect function as a parameter works, but then I have to pass it through the background worker and the report progress function; it is just messy and unclean. Is there a better way to do this? Any help is appreciated and thanks in advance.
Class where I call the connection function from(also my WPF class):
public partial class agentRadio : Window
{
private void connectButton_Click(object sender, RoutedEventArgs e) //Connect button clicked
{
agentradioread.connect((string)portsOpen.SelectedValue, this);
}
}
Class that handles my serial interaction:
class agentRadioRead //Handles connection and reading of device values
{
/*Local variable declarations*/
SerialPort agentSerial;
BackgroundWorker connectWorker;
string resultMessage = "Error: The connect function has completed without setting this status message properly.";
byte[] data = new byte[2246];
/*Public methods*/
public void connect(string selectedPort, agentRadio agentR) //Connects device, reads values, stores values, displays status message
{
agentSerial = new SerialPort(selectedPort, 9600, Parity.None, 8, StopBits.One);
connectWorker = new BackgroundWorker();
//connectWorker.WorkerReportsProgress = true;
connectWorker.DoWork += new DoWorkEventHandler(initialRead);
//connectWorker.ProgressChanged += new ProgressChangedEventHandler(reportProgress);
connectWorker.RunWorkerAsync(agentR);
}
/*Private methods*/
void initialRead(object sender, DoWorkEventArgs e)
{
agentSerial.Open();
agentSerial.BaseStream.Flush();
byte[] result = new byte[7];
byte questionMark = 63;
agentSerial.BaseStream.WriteByte(questionMark);
System.Threading.Thread.Sleep(100);
agentSerial.BaseStream.Read(result, 0, 7);
string system = "";
foreach (byte letter in result)
{
system += Convert.ToChar(letter).ToString();
}
bool read = readPort();
if (read)
{
int i = 1;
foreach (byte value in data)
{
storeData(i, value);
i++;
}
}
MessageBox.Show(resultMessage, "Status Message", MessageBoxButton.OK, MessageBoxImage.Information);
}
bool readPort()
{
bool succesfulRead = false;
agentSerial.BaseStream.Flush();
agentSerial.BaseStream.Write(Global.READ_VALUES, 0, Global.READ_VALUES.Length); //begin read values
byte key = (byte)agentSerial.BaseStream.ReadByte();
if (Global.START_COMMAND == key) //Verify continue key
{
for (int i = 0; i < 2246; i++) //Loop through values
{
try
{
data[i] = (byte)agentSerial.BaseStream.ReadByte();
agentSerial.BaseStream.Write(Global.GO_AHEAD, 0, Global.GO_AHEAD.Length);
agentSerial.BaseStream.Flush();
}
catch
{
resultMessage = "An error occured, while reading the device settings." + i;
break;
}
}
if (data[2245] != Global.FINISH_COMMAND)
{
resultMessage = "An error occured, while reading the device settings." + 2245;
}
else
{
succesfulRead = true;
}
}
else //Key failed and displays error
{
resultMessage = "An error occured, are you sure you are trying to connect to an Agent (Radio Version)? If so make sure you have followed the steps listed above.";
}
return succesfulRead;
}
void storeData(int iteration, byte value)
{
if (iteration > 0 && iteration < 385) //read schedule
{
double pos = (iteration - 1) / 48;
int i = (int)Math.Floor(pos);
int j = (iteration - 1) - (i * 48);
Create.schedule[i, j] = value;
}
if (iteration > 384 && iteration < 1285) //read alarm history
{
double pos = (iteration - 385) / 9;
int i = (int)Math.Floor(pos);
int j = (iteration - 385) - (i * 9);
Create.alarms[i, j] = value;
}
if (iteration > 1284 && iteration < 1345) //read error log
{
double pos = (iteration - 1285) / 6;
int i = (int)Math.Floor(pos);
int j = (iteration - 1285) - (i * 6);
Create.errors[i, j] = value;
}
if (iteration > 1344 && iteration < 1945) //read voltage history
{
double pos = (iteration - 1345) / 6;
int i = (int)Math.Floor(pos);
int j = (iteration - 1345) - (i * 6);
Create.voltage[i, j] = value;
}
if (iteration > 1944 && iteration < 1973) //read holidays
{
Create.holidays[iteration - 1945] = value;
}
if (iteration > 1972 && iteration < 2168) //read message sequences
{
double pos = (iteration - 1973) / 15;
int i = (int)Math.Floor(pos);
int j = (iteration - 1973) - (i * 15);
Create.messages[i, j] = value;
}
if (iteration > 2167 && iteration < 2196) //read message info
{
Create.recordings[iteration - 2168] = value;
}
if (iteration > 2195 && iteration < 2246) //read sysval
{
Create.sysval[iteration - 2196] = value;
}
if (iteration == 2246 && value == Global.FINISH_COMMAND)
{
if (Global.restoring)
{
resultMessage = "Your device has been succesfully restored.";
}
else
{
resultMessage = "Your device has been succesfully connected, and all settings have been loaded from the device.";
}
}
else
{
resultMessage = "An error occured, while reading the device settings." + "Storing";
}
}
void reportProgress(object sender, ProgressChangedEventArgs e)
{
}
}
I would do it the other way round.
Initialize the worker thread from within the agentRadio window.
Have all the functionality related to device interation within agentRadioRead class.
Take out all code that references the form window from it.
Create an object of this agentRadioRead class and pass it to the worker thread.
Use workerthread’s reportprogress event to report status changes to the agentRadio window.
Have the event handlers within agentRadio then do any UI updates.