I have a button on my program that checks a port. but if I put a port that is closed and I click to test it, if it is open I immediately get the green button. If it is not open instead the program is "freezed" for about ten seconds and then it gives me the red button. The problem is that if by mistake I click on the button while the program is in this phase of "freeze", then when it ends, restarts from the beginning and re-freezes, probably because it still felt the button click for the second time. how can I prevent this from happening?
button_click
private void bt_check_port_Click(object sender, EventArgs e)
{
bt_check_port.BackColor = SystemColors.Control;
TcpClient tcpClient = new TcpClient();
try
{
tcpClient.Connect(tb_ip_test.Text, Int32.Parse(tb_port_test.Text));
bt_check_port.BackColor = Color.Green;
}
catch (Exception)
{
bt_check_port.BackColor = Color.Red;
}
}
First you should go async, so you don't block the gui for long running tasks.
Then bypass the code while its executing, so it's not executed in parallel.
Also you should visibly inform the user that the button is currently not working(e.g. disable the button or display a wait indicator).
something like this:
private bool isWorking = false;
private async void bt_check_port_Click(object sender, EventArgs e)
{
if (!isWorking)
{
isWorking = true;
try
{
bt_check_port.Enabled = false;
bt_check_port.BackColor = SystemColors.Control;
string ip = tb_ip_test.Text;
string port = tb_port_test.Text;
bool portAwailable = await Task.Run<bool>(() =>
{
TcpClient tcpClient = new TcpClient();
try
{
tcpClient.Connect(ip, Int32.Parse(port));
return true;
}
catch (Exception)
{
return false;
}
});
bt_check_port.BackColor = portAwailable ? Color.Green : Color.Red;
}
finally
{
isWorking = false;
bt_check_port.Enabled = true;
}
}
}
Related
I have an application where user can click on a Scan button to scan the image to preview in the application. When user clicks, usually a "Preparing to scan" message will be shown and goes away when the scan is 100% complete.
The scan works fine. The problem if I stress test it by pressing the scan button many times while it's doing it's work, the application completely hangs and the message just stays there and I had to restart my whole application.
The code: It's just a small section
private void ScanStripButton_Click(object sender, EventArgs e)
{
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
}
Any idea on how to prevent this issue?
Appreciate the help
EDIT:
public void StartTwainScan()
{
Boolean EnableUI = false;
Boolean ADF = false;
Boolean EnableDuplex = false;
if (Properties.Settings.Default.TwainShow.Equals("1"))
{
EnableUI = true;
}
if (Properties.Settings.Default.ScanType.Equals("2"))
{
ADF = true;
}
if (Properties.Settings.Default.DuplexEnable.Equals("1"))
{
EnableDuplex = true;
}
var rs = new ResolutionSettings
{
Dpi = GetResolution(),
ColourSetting = GetColorType()
};
var pg = new PageSettings()
{
Size = GetPageSize()
};
var settings = new ScanSettings
{
UseDocumentFeeder = ADF,
ShowTwainUI = EnableUI,
ShowProgressIndicatorUI = true,
UseDuplex = EnableDuplex,
Resolution = rs,
Page = pg
};
try
{
TwainHandler.StartScanning(settings);
}
catch (TwainException ex)
{
MessageBox.Show(ex.Message);
//Enabled = true;
//BringToFront();
}
}
This isn't going to be the correct answer, but you haven't shown enough code to give you the right code. It should point you in the right direction.
private void ScanStripButton_Click(object sender, EventArgs e)
{
ScanStripButton.Enabled = false;
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
ScanStripButton.Enabled = true;
}
Basically you disable the button when the scan starts and enable it when it finishes.
private async void ScanStripButton_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
});
}
or
private bool clicked = false;
private void ScanStripButton_Click(object sender, EventArgs e)
{
try
{
if(clicked)
return;
clicked = true;
if (SCAN_INTO_BATCH)
{
GENERATE_BATCH_FOLDER = true;
StartTwainScan();
}
}
finally
{
clicked = false;
}
}
I had done a quick-search and still cant find the answer for my question .
Serial port variable
int close;
SerialPort _serialPort = new SerialPort("COM1", 1200, Parity.None, 8, StopBits.One);
Serial port delegate code
private void si_DataReceived(string data)
{
if (close == 1)
{
string d1 = data.Trim().Replace("TT", "");
d1 = d1.Replace("Tl3", "");
txtCan.Text = d1;
}
else
{
return;
}
}
private delegate void SetTextDeleg(string text);
void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = _serialPort.ReadLine();
this.BeginInvoke(new SetTextDeleg(si_DataReceived), new object[] { data });
}
Connect button code
private void button4_Click(object sender, EventArgs e)
{
if (button4.Text == "Close Connection")
{
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
close=0;
try
{
string d1 = txtCan.Text;
double r1 = Convert.ToDouble(d1) * 10;
txtCan.Text = Math.Round(r1, 3).ToString();
button4.Text = "Open Connection";
button1.Enabled = true;
readOnly(true);
}
catch (Exception ex)
{
button4.Text = "Open Connection";
button1.Enabled = true;
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
MessageBox.Show("Cant connect.");
}
}
else
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.MarqueeAnimationSpeed = 30;
close = 1;
txtCan.Text = "";
txtCan.Focus();
readOnly(false);
button1.Enabled = false;
button4.Text = "Close Connection";
try
{
if(!_serialPort.IsOpen)
{
_serialPort.Handshake = Handshake.None;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(sp_DataReceived);
_serialPort.Open();
}
}
catch
{
button4.Text = "Open Connection";
button1.Enabled = true;
readOnly(true);
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.MarqueeAnimationSpeed = 0;
MessageBox.Show("Cant connect.");
}
}
}
My solution to close a com port, but it will fail if I re-open a form in countable times (like twice or triple times then it will crash)
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (_serialPort.IsOpen)
{
e.Cancel = true;
Thread CloseDown = new Thread(new ThreadStart(CloseSerialOnExit));
CloseDown.Start();
}
}
private void CloseSerialOnExit()
{
try
{
backgroundWorker1.RunWorkerAsync();
}
catch (Exception ex)
{
}
this.BeginInvoke(new EventHandler(NowClose));
}
private void NowClose(object sender, EventArgs e)
{
this.Close(); //now close the form
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
_serialPort.Close();
}
string data = _serialPort.ReadLine();
There is no lack of potential trouble with this statement. You have a pretty nasty failure-mode on your hands when this call doesn't complete. It doesn't have to, you could turn off the serial device at just the wrong time, jerk the cable, get the line terminator corrupted and you'll have a pretty big headache.
The SerialPort.Close() method cannot complete until any of the event handlers stop running. This can significantly increase the odds for deadlock. Using the ReadLine() method is fine, but then you also have to set the ReadTimeout property to, say, 10 seconds so you can be sure that accidents don't turn into undebuggable problems. Let the TimeoutException either terminate your program or set a "serial port is dead" status variable.
Further improve the odds for success by disassociating the lifetime of the SerialPort with the lifetime of your form. In general the only sensible thing to do is to create the instance at program startup and not close it until your program terminates. Just keep it in a separate class, it can be static to make it easy to use.
And, unintuitively, it is now no longer important to call Close() at all. The finalizer will take care of it.
Also make sure that, if you use a USB emulator, to never disconnect it without going through the Safely Remove Hardware tray icon. USB drivers generally deal with a surprise removal very poorly. Some are so poor that they make the device disappear even though you have it opened. And trying to close it always fails, you cannot cleanly exit your program anymore.
this is my first interaction here! I'm learning C# by myself, there will be a lot of errors beside to the bug i'm trying to get rid of, please be patient :)
I'm developing a very basic app that let you interact with serial ports, something like the tool integrated in Arduino.
There is a button that is meant to Connect/Disconnect, it lanches/stops a Backgroundworker that keeps the form updated with new data. I've tryed to move .close(); every where in the code, but nothing changed, when I try to open it again it catches the Exception. And other apps con't access too. I think that I simply don't know what I'm doing :)
Can you help me releasing the resource?
The code involved in this operation:
private void ConnectB_Click(object sender, EventArgs e)
{
if (!connected)
{
int baud = Convert.ToInt32(baudRate.SelectedItem.ToString());
COMport = new SerialPort(COMpick.SelectedItem.ToString(), baud, Parity.None, 8, StopBits.One);
try
{
COMport.Open();
connected = true;
ConnectB.Text = "Disconnect";
}
catch (ArgumentOutOfRangeException)
{
MessageBox.Show("Baud rate not valid.");
connected = false;
}
catch (ArgumentException)
{
MessageBox.Show("Port name not valid.");
connected = false;
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Access denied, try close applications that may using the port.");
connected = false;
}
if (backWorker.IsBusy != true)
{
backWorker.RunWorkerAsync();
}
}
else
{
connected = false;
backWorker.CancelAsync();
ConnectB.Text = "Connect";
}
}
private void backWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
if (worker.CancellationPending == true)
{
e.Cancel = true;
break;
}
else if(COMport.IsOpen)
{
// Get data and print it in the form
try
{
inbox = COMport.ReadLine() + '\n';
}
catch (InvalidOperationException) { }
//Scroll down the form, passing something useless to make it work
worker.ReportProgress(inbox.Length);
}
}
}
private void backWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
this.COMport.Close();
this.COMport.Dispose();
}
Thank you!
I read time from php with C#. I have to show MessageBox before Logoff windows when the time is equal. But when I run program it show same MessageBox 2 time. I want to show MessageBox 1 time only before Logoff. I set Interval is 30,000. How to do it? This is my code
private void timer1_Tick(object sender, EventArgs e)
{
bool showingBox = false;
timer1.Start();
WebClient client = new WebClient();
Stream stream = client.OpenRead("http://172.22.22.20/time.php");
StreamReader reader = new StreamReader(stream);
String content = reader.ReadToEnd();
//textBox1.Text = content;
if (showingBox) return;
showingBox = true;
try
{
if (content == "08:00")
{
MessageBox.Show(new Form() { TopMost = true }, "11111"); // This will show 2 Message Box when time = 08.00
}
}
finally
{
showingBox = false;
}
if (content == "08:05")
{
ExitWindowsEx(4, 0);
}
timer1.Enabled = false;
}
}
}
I don't know if i understand your question right, but could it be that you start the timer twice ?
As far as i can see you do start the timer again in your timer_tick method
private void timer1_Tick(object sender, EventArgs e)
{
bool showingBox = false;
timer1.Start(); // <-- second time startet.
Why you using timer1.Start(); in timer1_Tick Event?
I remove timer1.Start() but it also show twice messagebox . I change the code like this flag = true; have to run before show message box . Now it work!!.
if (content == "10:09")
{
if (!flag)
{
flag = true;
MessageBox.Show(new Form() { TopMost = true }, "11111" +flag);
}
}
I have a test web connection form in c#. I want to show a loading window while my connection is being checked, and then show the result of checking.
This is my code for testing the web connection:
public bool ConnectionAvailable(string strServer)
{
try
{
HttpWebRequest reqFP = (HttpWebRequest)HttpWebRequest.Create(strServer);
HttpWebResponse rspFP = (HttpWebResponse)reqFP.GetResponse();
if (HttpStatusCode.OK == rspFP.StatusCode)
{
// HTTP = 200 - Internet connection available, server online
rspFP.Close();
return true;
}
else
{
// Other status - Server or connection not available
rspFP.Close();
return false;
}
}
catch (WebException)
{
// Exception - connection not available
return false;
}
}
And this:
private void button1_Click(object sender, EventArgs e)
{
string url = "Web-url";
label1.Text = "Checking ...";
button1.Enabled = false;
if (ConnectionAvailable(url))
{
WebClient w = new WebClient();
w.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
label1.Text = w.UploadString(url, "post", "SN=" + textBox1.Text);
button1.Enabled = true;
}
else
{
label1.Text = "Conntion fail";
button1.Enabled = true;
}
}
On a windows forms application the user interface runs on one thread, if you try to run a long running process, which checking the web connection might end up being this will cause the form to freeze until it completes the work.
So, I'd start a new thread that does the check. then raise an event to return the result. while all that's happening you can do what you like with the user interface, such as a loading graphic, or even allow the user to continue using features that don't require the internet connection.
Create EventArgs class of your own so you can pass back the result:
public class ConnectionResultEventArgs : EventArgs
{
public bool Available { get; set; }
}
Then in your form class, create your event, handlers and the method to action when the event arrives
//Create Event and Handler
public delegate void ConnectionResultEventHandler(object sender, ConnectionResultEventArgs e);
public event ConnectionResultEventHandler ConnectionResultEvent;
//Method to run when the event has been receieved, include a delegate in case you try to interact with the UI thread
delegate void ConnectionResultDelegate(object sender, ConnectionResultEventArgs e);
void ConnectionResultReceived(object sender, ConnectionResultEventArgs e)
{
//Check if the request has come from a seperate thread, if so this will raise an exception unless you invoke.
if (InvokeRequired)
{
BeginInvoke(new ConnectionResultDelegate(ConnectionResultReceived), new object[] { this, e });
return;
}
//Do Stuff
if (e.Available)
{
label1.Text = "Connection Good!";
return;
}
label1.Text = "Connection Bad";
}
Subscribe to the event when your form loads:
private void Form1_Load(object sender, EventArgs e)
{
//Subscribe to the the results event.
ConnectionResultEvent += ConnectionResultReceived;
}
and then setup the worker thread:
//Check the connection
void BeginCheck()
{
try
{
HttpWebRequest reqFP = (HttpWebRequest)HttpWebRequest.Create("http://google.co.uk");
HttpWebResponse rspFP = (HttpWebResponse)reqFP.GetResponse();
if (HttpStatusCode.OK == rspFP.StatusCode)
{
// HTTP = 200 - Internet connection available, server online
rspFP.Close();
ConnectionResultEvent(this, new ConnectionResultEventArgs {Available = true});
}
else
{
// Other status - Server or connection not available
rspFP.Close();
ConnectionResultEvent(this, new ConnectionResultEventArgs { Available = false });
}
}
catch (WebException)
{
// Exception - connection not available
//Raise the Event - Connection False
ConnectionResultEvent(this, new ConnectionResultEventArgs { Available = false });
}
}
private void button1_Click(object sender, EventArgs e)
{
//loading graphic, screen or whatever
label1.Text = "Checking Connection...";
//Begin the checks - Start this in a new thread
Thread t = new Thread(BeginCheck);
t.Start();
}
I am thinking of threading! One thread checks the connection while the other one is showing the loading window. If for example the connection has been established you can notify the other thread and show the result.