A lot of good programmers (including a lot of good members of Stackoverflow) are against using Application.DoEvents()
whatever the circumstances are. Actually it is even supported with plenty of articles in the net, like this one, this famous debate on SO, ...
Though, I'm stuck in a case, where (I) think DoEvents()
is the unique exit (lack of experience). That's enough as introduction, let's see some coding.
I have a 'serialPort' component to connect with a controller through serial communication, send command and wait for its response, that's all.
string response = "";
bool respFlag;
private string sendCommand(string command)
{
respFlag = false; //initialize respFlag
serialPort1.Write(command); // send the command
Stopwatch timer = Stopwatch.StartNew(); // start a timer
while(true)
{
// break from the loop if receive a response
if(respFlag) break;
// timeOut error if no response for more than 500msec
if(timer.ElapsedMilliseconds >= 500) break;
// here comes the UGLY part
Application.DoEvents();
}
return response;
}
in DataReceived method of my serialPort, I read the existing response and break the loop
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
response = serialPort1.ReadExisting();
// set the flag to true to exit the infinite loop in sendCommand
respFlag = true;
}
It's not exactly like this, but this is a sample code that shows how I sned-receive via serial communication, would you kindly show me where am I forcing myself into this pitfall?
If you are using .NET 4.5 it is really easy to do with async/await and a TaskCompletionSource and async/await.
TaskCompletionSource<string> resultTcs = new TaskCompletionSource<string>();
private async Task<string> SendCommandAsync(string command)
{
serialPort1.Write(command); // send the command
var timeout = Task.Delay(500);
//Wait for either the task to finish or the timeout to happen.
var result = await Task.WhenAny(resultTcs.Task, timeout).ConfigureAwait(false);
//Was the first task that finished the timeout task.
if (result == timeout)
{
throw new TimeoutException(); //Or whatever you want done on timeout.
}
else
{
//This await is "free" because the task is already complete.
//We could have done ((Task<string>)result).Result but I
//don't like to use .Result in async code even if I know I won't block.
return await (Task<string>)result;
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
var response = serialPort1.ReadExisting();
tcs.SetResult(response);
//reset the task completion source for another call.
resultTcs = new TaskCompletionSource<string>();
}
You should use the async
I/O methods. Asynchronously wait for Task<T> to complete with timeout is a good example.
I assume the answer is to run that loop in a different thread and send a message to the UI when the response is available. This assumes you cant do async IO for some reason
来源:https://stackoverflow.com/questions/28357292/avoid-application-doevents-in-c-sharp