I have a problem using Thread.sleep(seconds), it pauses all my execution in sleeping state. But I tried another solutions also using for loop, however what I'm expecting it's not working.
When the login button is clicked:
Action report="on progressing";
After another 2 seconds it will be "trying to connect to the database"
then after opening database it will be like "database connected successfully"
Here is the code:
private void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
if(userText.Text!=String.Empty && passText.Password!=String.Empty){
ProgressForm.Visibility = System.Windows.Visibility.Visible;
LoginForm.Visibility = System.Windows.Visibility.Hidden;
delay(2);
actionReport.Text = "Try to Connecting the database";
String ConnectionString = "server=127.0.0.1;uid=root;pwd='';database=smsdb;";
MySqlConnection con = new MySqlConnection(ConnectionString);
try {
con.Open();
delay(2);
actionReport.Text = "Database Connected Sucessfully";
}
catch(MySqlException sqle){
actionReport.Text = sqle.Message;
}
}
else {
MessageBox.Show("Please enter the user name and password to verify","Notification",MessageBoxButton.OK,MessageBoxImage.Information);
}
}
private void delay(int seconds)
{
for(long i=0;i<seconds*3600; i++){
//empty
}
Please someone help me.
await (introduced in C# 5.0) with Task.Delay makes this trivially easy:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
await Task.Delay(2);
actionReport.Text = "Connected";
}
For a C# 4.0 solution it's a tad messier, but not a whole lot:
public async void Loginbtn_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
actionReport.Text = "Trying to Connecting to the database";
Task.Delay(2).ContinueWith(_ =>
{
actionReport.Text = "Connected";
}, CancellationToken.None
, TaskContinuationOptions.None
, TaskScheduler.FromCurrentSynchronizationContext());
}
The key point here is that at no point are you blocking the UI thread, you're simply letting the UI thread continue on processing events for two seconds before giving it something to do.
I found answer like this
delay("Try to Connecting the database");
delay like this.
public void delay(string message) {
var frame = new DispatcherFrame();
new Thread((ThreadStart)(() =>
{
Thread.Sleep(TimeSpan.FromSeconds(2));
frame.Continue = false;
})).Start();
Dispatcher.PushFrame(frame);
actionReport.Text=message;
}
Thanks friends!
to reply me.
You first need to look up and understand performing processing on a background thread. The main rules being;
You should never block the UI
don't try to talk to the UI thread from a background thread
If you call Thread.Sleep, it's probably wrong
Your questions demonstrate an opportunity for you to learn new architectural patterns. These look like good candidates;
http://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners
http://www.codeproject.com/Articles/26148/Beginners-Guide-to-Threading-in-NET-Part-1-of-n
Related
This question already has answers here:
WinForm Application UI Hangs during Long-Running Operation
(3 answers)
Closed 5 years ago.
My program is suppose to perform tests on 8 electronic products of the same model simultaneously. The previous programmer has implemented some form of multi-threading in the program to accomplish this. However, when 5 slots or more are being tested, the UI becomes unresponsive and the results being written to a text file may get corrupted.
Below I will insert a pseudo-code on what's going on in the program.
private void button1_Click(object sender, EventArgs e)
{
//create_thread_1 <= mainFunction 1
//start thread 1
}
private void button2_Click(object sender, EventArgs e)
{
//create_thread_2 <= mainFunction 2
//start thread 2
}
private void button3_Click(object sender, EventArgs e)
{
//create_thread_3 <= mainFunction 3
//start thread 3
}
private void mainFunction1
{
//perform test A
//write test A result to textFile1 //calls writeToTextFile1
//perform test B
//write test B result to textFile1 //calls writeToTextFile1
//continues on and finishes all tests
//aborts thread1
//end
}
private void mainFunction2
{
//perform test A
//write test A result to textFile2 //calls writeToTextFile2
//perform test B
//write test B result to textFile2 //calls writeToTextFile2
//continues on and finishes all tests
//aborts thread2
//end
}
private void mainFunction3
{
//perform test A
//write test A result to textFile3 //calls writeToTextFile3
//perform test B
//write test B result to textFile3 //calls writeToTextFile3
//continues on and finishes all tests
//aborts thread3
//end
}
private void writeToTextFile1
{
//creates and saves results into textFile1
}
private void writeToTextFile2
{
//creates and saves results into textFile2
}
private void writeToTextFile3
{
//creates and saves results into textFile3
}
My theory is that only a single thread can open and write data into a text file at a single time, so when another thread have to write data, that thread has to wait and causes the UI to become unresponsive. Am I right here? If I'm not, any advice is greatly appreciated.
One of the solutions that I have read online is to declare the WriteToTextFile function as a new Thread so that other main threads can wait for each other without slowing down the UI. Is this the correct approach?
EDIT: added the important parts of the coding for better understanding..This code runs for one slot only but the other 9 slots basically uses the same code here
private void button1_Click(object sender, EventArgs e)
{
if (this.button1.Text == "START")
{
this.txtSerial1.ReadOnly = false;
this.txtSerial1.Select();
MessageBox.Show("SLOT 1: Scan the serial number and press ENTER", "3458A
Heat Rack", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
else if (System.Windows.Forms.DialogResult.OK == MessageBox.Show("SLOT 1: Are
you sure about stopping?", "3458A Heat Rack",
MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation))
{
this.call_main1.Abort();
this.sentry1.Close();
this.sentry1.Dispose();
MessageBox.Show("SLOT 1: Unit can be safely removed now", "3458A Heat
Rack", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
this.txtSerial1.Clear();
this.txtStart1.Clear();
this.txtStatus1.Clear();
this.info1.Clear();
this.button1.Text = "START";
this.button1.BackColor = this.startColour;
this.txtStatus1.BackColor = Control.DefaultBackColor;
}
}
private void textBox1_KeyPress(object sender, KeyPressEventArgs e)
{
int num;
int test_num = default(int);
double resultrelay = default(double);
if (e.KeyChar == '\r')
{
if (this.txtSerial1.Text.Length == 0)
{
this.txtSerial1.ReadOnly = true;
}
else if (this.txtSerial1.Text.Length >= 10)
{
try
{
this.sentry1 = new DirectIO(string.Concat("GPIB",
this.busNumber_Slot1, "::22::INSTR"));
this.terminal1 = new DirectIO(string.Concat("GPIB0::14::INSTR"));
num = 1;
}
catch (Exception exception)
{
num = 0;
}
if (num != 1)
{
MessageBox.Show("SLOT 1: DUT Not Present !!", "3458A Heat Rack",
MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
this.txtSerial1.Clear();
this.txtSerial1.Select();
this.txtSerial1.ReadOnly = true;
}
else
{
this.button1.Select();
this.button1.Text = "RUNNING";
this.button1.BackColor = this.runningColour;
this.txtSerial1.Text = this.txtSerial1.Text.ToUpper();
this.txtStart1.Text = DateTime.Now.ToString();
this.txtSerial1.ReadOnly = true;
string txtBox1_serial = this.txtSerial1.Text;
this.call_main1 = new Thread(() => this.main_Program_slot1(sentry1,
terminal1, txtBox1_serial, 1, test_num,
resultrelay));
this.call_main1.Start();
}
}
else
{
MessageBox.Show("SLOT 1: Unit Serial Number Is Incorrect!!", "3458A
Heat Rack", MessageBoxButtons.OK,
MessageBoxIcon.Asterisk);
this.txtSerial1.Clear();
this.txtSerial1.Select();
}
}
}
public void slot1(string test) //function to update GUI
{
if (!base.InvokeRequired)
{
this.info1.Text = test;
}
else
{
Form1.test1 updateTestType = new Form1.test1(this.slot1);
object[] objArray = new object[] { test };
base.Invoke(updateTestType, objArray);
}
}
private void write_TestResultDetails1(string serialnumber, double resultLatest1)
{
//update results into textfile
}
private void main_Program_slot1(DirectIO sentry1, DirectIO terminal1, string sernum, int slot_Number, int test_num, double resultrelay)
{
for (int i = 1; i <= loop_Count; i++)
{
slot1("TEST A");
//performs testA
//calls write_TestResultDetails1
slot1("TEST B");
//performs testB
//calls write_TestResultDetails1
}
}
Hope this coding can help you guys to understand my problem better..
PS: seems like changing to using BackGroundWorker instead of making my own threads will be a better choice for this kind of program.
Windows forms programming has a few gotchas and keeping a UI responsive is tough. To help you debug this issue, I recommend you name your thread in form load so you can easily find it in the debugger (double click your form in the designer to get form load then call System.Threading.Thread.CurrentThread.Name = "My UI Thread". Launch your application and then when the UI hangs, break in the debugger. You can then observe the stacktrace of the UI Thread to find out where it is working (and where you need to use a thread to keep the UI responsive.
My hunch is that you have either used a synchronisation primitive incorrectly waiting for an answer on a thread, or you have accidentally launched some work without a thread which is hanging the UI.
There is a control called a BackgroundWorker which can be used to do work on a thread easily and then report the progress back with an event safely. This cuts down on the synchronisation work you need to do which might be helpful.
Totally agree with the previous comments btw, please post your actual code, just redact the method names etc. as the most likely issue is that your psuedo code and your actual code don't match.
I/O intensive tasks are perfect for asynchronous actions, i.e. writeToTextFile1(), writeToTextFile2(), and writeToTextFile3() can all be executed on different threads.
in your solution, the error might be caused from the fact that you wrapped two/three I/O method calls inside one thread.
I suggest you adopt the following pattern.
take writeToTextFile1() for example, I would use async/await pattern to define this method:
private async Task writeToTextFile1Async(string resultValue)
{
await Task.Run(() => {
//create and saves results into textFile1
});
}
rewrite mainFunction1() as follows:
private async Task mainFunction1Async()
{
string resultA = "***";
await writeToTextFile1Async(resultA);
string resultB = "***";
await writeToTextFile1Async(resultB);
//perform other things
}
Call this function inside Button1 click event handler:
private async void button1_Click(object sender, EventArgs e)
{
await mainFunction1Async();
}
I have a Login Form that checks AutoLogInStatus in database. If the AutoLogInStatus is set to true the main form will show if false the login form will show.
This the code in my Form_Load events:
if (Convert.ToBoolean(UserAutoLogon()) == true)
{
this.Hide();
frmMain.Show();
}
else
{
this.Show();
}
All works good, except if the SQL server is not running. The login forms shows with all white and it freezes.
How will I handle this?
Thanks.
Consider using async-await so that your UI thread is not blocked while the SQL connection is being established:
private async void Form_Load(object sender, EventArgs e)
{
var frmMain = new frmMain();
var result = await UserAutoLogon();
if (result == true)
{
this.Hide();
frmMain.Show();
}
else
{
this.Show();
}
}
private Task<bool> UserAutoLogon()
{
return Task.Run(() =>
{
Thread.Sleep(10000); // Db connection delay
return true;
});
}
UPDATE
The UserAutoLogon() method's implementation was given so that it simulates the delay - you may use await connection.OpenAsync() as suggested by Scott Chamberlain in the comments.
I'm starting my adventure with mobile developing and already faced a problem. I know in WPF I would use BackgroundWorker to update the UI, but how does it work with Android using Xamarin?
I've found many advises but none of these worked for me. The code below won't change the text while the rest is being executed, it just awaits and performs all at once, which isn't what I want.
private void Btn_Click(object sender, System.EventArgs e)
{
RunOnUiThread(() => txt.Text = "Connecting...");
//txt.Text = sql.testConnectionWithResult();
if (sql.testConnection())
{
txt.Text = "Connected";
load();
}
else
txt.Text = "SQL Connection error";
}
Here your action comes from a button click action, so you don't need to use RunOnUiThread because you are ready working on this one.
If I understand correctly your code it should look like this :
private void Btn_Click(object sender, System.EventArgs e)
{
txt.Text = "Connecting...";
//do your sql call in a new task
Task.Run(() => {
if (sql.testConnection())
{
//text is part of the UI, so you need to run this code in the UI thread
RunOnUiThread((() => txt.Text = "Connected"; );
load();
}
else{
//text is part of the UI, so you need to run this code in the UI thread
RunOnUiThread((() => txt.Text = "SQL Connection error"; );
}
});
}
The code inside Task.Run will be called asynchronously without blocking the ui.
You can use await word inside the Task.Run if you need to wait for specific work before update UI elements.
There are many ways to do this, but in the form of your example code:
button.Click += (object sender, System.EventArgs e) =>
{
Task.Run(async () =>
{
RunOnUiThread(() => txt.Text = "Connecting...");
await Task.Delay(2500); // Simulate SQL Connection time
if (sql.testConnection())
{
RunOnUiThread(() => txt.Text = "Connected...");
await Task.Delay(2500); // Simulate SQL Load time
//load();
}
else
RunOnUiThread(() => txt.Text = "SQL Connection error");
});
};
FYI: There are some great libraries that can help create a reactive user experience, with ReactiveUI being at the top of my list as it also is a MVVM framework...
Like WPF Xamarin supports Async/Await too!
https://developer.xamarin.com/guides/cross-platform/advanced/async_support_overview/
https://developer.xamarin.com/samples/mobile/AsyncAwait/
first time using Stackoverflow so i'll try to do my best.
I was making a little app to ping some servers, the issue i'm having is that the GUI of the program locks up while it waits for a response.
This is what I have so far, Button_Click is the "Ping IP" button, ping_box is a textbox that will contain the response time, ip_address is a IP address in the form of a string.
private void Button_Click(object sender, RoutedEventArgs e)
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromSeconds(2))
{
using (Ping p = new Ping())
{
ping_box.Text = (p.Send(ip_address, 1000).RoundtripTime.ToString() + "ms\n");
if (ping_box.Text == "0ms\n")
{
ping_box.Text = "Server is offline or exceeds 1000ms.";
}
}
}
s.Stop();
}
So in its current state it pings the IP address repeatedly for two seconds and puts the response time into a textbox, during this time the GUI locks up though.
I need to recorrect this as I want the textbox with the response time to update with each ping (if the response time is 500 ms then the textbox should update four times).
I've tried to use Ping.SendAsync but could not get it to work, any pointers or help would be much appreciated :)
I think this should help...
You can modify it further as per your needs
private void button1_Click(object sender, EventArgs e)
{
AutoResetEvent waiter = new AutoResetEvent(false);
IPAddress ip = IPAddress.Parse("192.168.1.2");
var pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
pingSender.SendAsync(ip, 1000, waiter);
}
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If an error occurred, display the exception to the user.
if (e.Error != null)
{
MessageBox.Show(string.Format("Ping failed: {0}", e.Error.ToString()),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
DisplayReply(e.Reply);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
public void DisplayReply(PingReply reply)
{
if (reply == null)
return;
ping_box.Text = string.Format("Ping status: {0}, RoundTrip time: {1}",
reply.Status,
reply.RoundtripTime.ToString());
}
Ping
Allows an application to determine whether a remote computer is
accessible over the network.
When you called Ping, your Main Thread (and that is your UI Thread) has been halt and wait for ping respond, that's why your application freeze.
solution:
You need to put Ping in another Thread
I'm working on windows from application in .net framework 2.0.
There is some operations run in background like database backup, progress bar and label text update etc.
But When I use cross thread then my application doesn't respond(busy icon) until background operations complete
This is example code
private void button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(UpdateInfo));
t.Start();
}
private void UpdateInfo()
{
if (this.InvokeRequired)
{
this.Invoke(new MethodInvoker(UpdateInfo));
}
else
{
// send query to database here for taking backup that could take time
// update progress bar
//I'm also using sqlconnection InfoMessage here
label1.Text = "Text upading......
}
}
private void OnInfoMessage(sender As Object, e As SqlInfoMessageEventArgs)
{
}
Scenario:
Scenario is user could cancel operation but it can't due to application not responding
================Update Code==========================================
My Code is like
private void btnBackup_Click(object sender, EventArgs e)
{
Thread t = new Thread(new ThreadStart(MyThreadFunc));
t.Start();
}
public void MyThreadFunc()
{
if (this.InvokeRequired) {
this.Invoke(new MethodInvoker(Backup));
} else {
Backup();
}
}
public void Backup()
{
string databaseName = cbDatabase.Text;// getting the name of database for backup
SaveFileDialog1.ShowDialog(); // dialog will open
string backupFileName = SaveFileDialog1.FileName; // getting location of backup
//============ database query==================
SqlConnection con = new SqlConnection(conString);
con.FireInfoMessageEventOnUserErrors = true;
con.InfoMessage += OnInfoMessage;
con.Open();
query = string.Format("backup database {0} to disk = {1}", databaseName,backupFileName);
using (cmd == new SqlCommand(query, con)) {
cmd.CommandTimeout = 0;
cmd.ExecuteNonQuery();
}
con.Close();
con.InfoMessage -= OnInfoMessage;
con.FireInfoMessageEventOnUserErrors = false;
//============ Database operation end==================
}
private void OnInfoMessage(object sender, SqlInfoMessageEventArgs e)
{
lblStatusMsg.Text = e.Message; // mostly messages are like. 1 percent complete, 5 percent complete, 11 percent complete
foreach (SqlError info in e.Errors) {
if (info.Class > 10) {
// errror logging
} else {
Regex reger = new Regex("\\d+");
Match regerMatch = reger.Match(e.Message);
if (ProgressBar1.Value == 100) {
} else {
ProgressBar1.Value = regerMatch.Value;
}
}
}
}
Not responding issue until database operation completes
The purpose of the Invoke call is to have code run on the main thread. Your code is therefore creating a thread whose entire purpose is to force the main thread to run all the code.
Let's assume that you want to run a thread that, 10 seconds after it starts, updates a label's text to indicate completion. You still need to Invoke the label update, but that's the only thing that should be in the invoke.
In that case your thread function should look something like this:
private void MyThreadFunc()
{
// do something here
Thread.Sleep(10000);
// update the label:
if (label1.InvokeRequired)
Invoke(UpdateLabel);
else
UpdateLabel();
}
private void UpdateLabel()
{
label1.Text = "Something was finished.";
}
In other words, you need to separate out those things that have to run on the main thread (like anything that updates controls on your form) and Invoke only those bits. The rest of it should happen outside of the Invoke.
I guess I didn't make it clear.
The Invoke method is used to execute code in the context of the thread that owns the handle of the control or form that you're invoking on. You can use this to interact with controls on the UI, but you should only use it for that purpose. If you put all of the thread's close in an Invoke call then all of the thread's code will run in the UI thread, which makes it completely pointless to have a separate thread.
If you want to stop your application's UI from pausing while things happen - which is, after all, one of the main reasons to use a thread - then you should use the Invoke method only when absolutely necessary, and then only for very small sections of code. Call Invoke to update a control's parameters, interact with the non-threadsafe properties of the form, etc. You can use dialog boxes and so on directly from your other thread, although some prefer to use Invoke for those as well.
And if you're doing multiple invokes then you probably should write some helper methods to wrap the Invoke to clean things up. Something like:
public void Invoker(Action action)
{
if (InvokeRequired)
Invoke(action);
else
action();
}
public T Invoker<T>(Func<T> func)
{
if (InvokeRequired)
return (T)Invoke(func);
else
return func();
}
Now you can write your thread code with minimal impact like this:
public void ThreadFunc()
{
System.Threading.Thread.Sleep(1000);
Invoker(() => this.label1.Text = "Started");
for (int i = 1; i < 10; i++)
{
System.Threading.Thread.Sleep(1000);
Invoker(() => this.label1.Text = string.Format("Iteration {0}", i));
}
System.Threading.Thread.Sleep(1000);
Invoker(() => this.label1.Text = "Completed");
}
Or if you don't like lambda functions (for some reason) you can use methods like this:
public void Invoker<T>(Action<T> action, T p)
{
if (InvokeRequired)
Invoke(action, p);
else
action(p);
}
private void SetLabel(string value)
{
label1.Text = value;
}
And then in your code:
Invoker(SetLabel, "new text value");
The important part is to keep the code you're invoking be tiny or you'll end up blocking your main thread.