winforms - C# GUI refresh and async serial port communication -


i'm trying create application communicates hardware via serial port , reports results gui.

currently moving through gui made keyevents trigger drawing of next "page" of gui. @ 1 step (after key pressed) need draw new page , send few commands via serial port.

the command sending done via :

port.write(data, 0, data.length); 

i wait answer waiting datareceivedhandler trigger - pins out there data awaiting , data being processed in method.

at first put sending & receiving command in function drawing page after "draw parts" made stuck - data being transfered, page wasn't drawn - frozen.

then made async method :

private async void senddata() {   await task.run(() => serialclass.sendandreceive(command));   // process reply etc. } 

which used :

public void loadpage() {   image = image.fromfile(path);   //do stuff on image using graphics, adding texts etc.   picturebox1.image = image;   senddata(); } 

it works fine, need "reload" page (to call again loadpage). if inside async method :

private async void senddata() {   await task.run(() => serialclass.sendandreceive(command));   // process reply etc.   loadpage(); } 

then image won't refreshed, though data send via serial port. possible somehow check if async function finished , trigger event reload page?

so far i've tried using backgroundworker work complete , property change. data send again, image wasn't reloaded. idea how can achieve that?

thanks in advance help, best regards

you need use state machine , delegates achieve trying do. see code below, recommend doing in separate thread other main. keep track of state you're in, , when response parse correct callback function , if expecting move onto next send command state.

private delegate void callbackfunction(string response);    //our generic delegate private callbackfunction callbackresponse;                  //instantiate our delegate private statemachine currentstate = atrhbpcalstatemachine.waiting;  serialport sp;  //our serial port  private enum statemachine {     waiting,     sendcmd1,     cmd1response,     sendcmd2,     cmd2response,     error }  private void do_state_machine() {     switch (statemachine)     {         case statemachine.waiting:             //do nothing             break;         case statemachine.sendcmd1:             callbackresponse = cmd1response;    //set our delegate first response             sp.write("send first command1");    //send our command through serial port              currentstate = statemachine.cmd1response;   //change cmd1 response state             break;         case statemachine.cmd1response:             //waiting response....you can put timeout here             break;         case statemachine.sendcmd2:             callbackresponse = cmd2response;    //set our delegate second response             sp.write("send command2");  //send our command through serial port              currentstate = statemachine.cmd2response;   //change cmd1 response state             break;         case statemachine.cmd2response:             //waiting response....you can put timeout here             break;         case statemachine.error:             //error occurred             break;     } }  private void cmd1response(string s) {     //parse string, make sure expect     //if is, set next state run next command     if(s.contains("expected"))     {         currentstate = statemachine.sendcmd2;     }     else     {         currentstate = statemachine.error;     } }  private void cmd2response(string s) {     //parse string, make sure expect     //if is, set next state run next command     if(s.contains("expected"))     {         currentstate = statemachine.waiting;         backgroundworker1.cancelasync();     }     else     {         currentstate = statemachine.error;     } }  //in case, build string builder until carriage return or colon character.  tells me //i got characters want response.  call delegate calls correct response //function.  datareceived event can fire mid response, need someway know when have whole //message. private void serialport1_datareceived(object sender, system.io.ports.serialdatareceivedeventargs e) {     string currentline = "";     string data = serialportsensor.readexisting();      data.replace("\n", "");      foreach (char c in data)     {         if (c == '\r' || c == ':')         {             sb.append(c);              currentline = sb.tostring();             sb.clear();              callbackresponse(currentline);  //calls our correct response function depending on current delegate assigned         }         else         {             sb.append(c);         }     } } 

i put in background worker, , when press button or can set current state sendcmd1.

button press

private void buttonstart_click(object sender, eventargs e) {     if(!backgroundworker1.isbusy)     {         currentstate = statemachine.sendcmd1;          backgroundworker1.runworkerasync();     } } 

background worker work event

private void backgroundworker1_dowork(object sender, doworkeventargs e) {     while (true)     {         if (backgroundworker1.cancellationpending)             break;          do_state_machine();         thread.sleep(100);     } } 

edit: can use invoke update gui background worker thread.

this.invoke((methodinvoker)delegate {     image = image.fromfile(path);     //do stuff on image using graphics, adding texts etc.     picturebox1.image = image; }); 

Comments