Here's a C# code, What happens is when qsubmit button is clicked, program straight away displays "wait..!".
When I debug the program it is found that when I click and function executes textbox1.text = "Hello"; but doesn't updates textbox, it updates only when the control goes off the event function, when that happens value of textbox has already been changed to "wait..!". I want to know why it doesn't updates textbox instantly(If that would have done, I would have seen the text during Thread.Sleep())
private void Button_QSubmit_Click(object sender, EventArgs e)
{
textBox1.Text = "Hello";
Thread.Sleep(1000);
textBox1.Text = "Wait..!";
}
The UI thread is responsible to redraw the windows. So as long as you are doing this inside the UI Thread (e.g. a Button click event), the process is busy with your code and the window is not drawn.
A easy solution could be the use of an Timer. Just add an timer and in the button click you start it (e.g. you set itup to fire in 1 second).
The Timer Event then will simply set the Text.
https://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx shows details about the Timer class.
You are hanging the UI Thread by calling Thread.Sleep from the Main Thread (UI), to update the text box you have to let the UI thread do its job outside your function to update the UI..anyway call Application.DoEvents() before the sleep. But calling Application.DoEvents() is a bad design
Related
I have a winforms application that was originally designed to be have different sequential functions triggered manually with buttons (4 buttons without corresponding backgroundworkers,4 buttons with corresponding backgroundworkers, 8 buttons total). Each button does some quick set up synchronously and then fires off a background worker to do the work asynchronously. This can be heavy work.
A decision was made to have an "express" option that does all the work of the 4 buttons with default options. Unfortunately I didn't design this as modular as I should have.
What I have done is have the ExpressButton call a 5th background worker, which in turn calls InvokeOnClick on each button in sequential order. Luckily the 4 non asynchronous buttons clicks get called first. I am using an AutoResetEvent to block the 5th backgroundworker while each sequential button is clicked.
Here is some pseudo code, buttons 1-4 don't call background workers, buttons 5-8 call backgroundworkers and _resetevent = new AutoResetEvent(false) in the global variables:
private void backgroundWorker5_DoWork(object sender, DoWorkEventArgs e)
{
ControlEventArgs automationcheck = new ControlEventArgs(expressButton);
InvokeOnClick(button1, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button2, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button3, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button4, null);
System.Threading.Thread.Sleep(500);
InvokeOnClick(button5, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button6, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button7, automationcheck);
_resetevent.WaitOne();
_resetevent.Reset();
InvokeOnClick(button8, automationcheck);
_resetevent.WaitOne();
_statusBox.AppendText("Finished" + Environment.NewLine);
}
So here is the strange thing. In the UI I have 2 textboxes where users enter information.
In backgroundworker1 (corresponding above to button5), I can access the .Text property of the first TextBox.
However in backgroundworker2 (corresponding to button6), I cannot access the .Text property of the other TextBox.
I can access it in the button6 click event all the way up until I call RunWorkerAsync().
As soon as I'm in the backgroundworker2 trying to access the TextBox.Text freezes the program up. No exception, it just stops.
Here is my theory :
backgroundworker1 is called/run with no parameters from button5 click event
backgroundworker2 is called/run with parameters from button6 click event
By passing an objectlist in RunWorkAsync(params[]) am I causing it to NOT pass some context of the original form control?
The funny thing here is that there is another textbox on the main form called statusBox that I can still access in backgroundworker2, in fact that's what I've been using for debugging purposes.
So to recap.
Button 9
Backgroundworker 5
Button 1
Button 2
Button 3
Button 4
Button 5
Backgroundworker 1
Can access TextBox.Text here
Button 6
Backgroundworker 2
Can't access TextBox.Text here
Button 7
Backgroundworker 3
unsure
Button 8
Backgroundworker 4
unsure
Worst case scenario :
Since button6 still has access to the textbox, I can grab the text out and pass it in the params list for runworkerasync. However I'd still like to know why 1 backgroundworker can see a textbox on the mainform and another can't.
Do as Austin said and Invoke() all the calls.
You're hitting this exception (i don't care if it's consistent) just randomly, any call to UI from a worker thread may lead to an exception as only the main thread must access the UI.
My bet is when you access the .Text property for the first time the control itself does not need to redraw, but the second time it needs, so you will end with a cross-threading exception.
I have a program that run in a loop. it's this
private void ReadCamAuto_Click(object sender, EventArgs e)
{
this.serialPort1.DataReceived -= new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
RunReadCamAuto = true;
while (RunReadCamAuto)
{
serialPort1.WriteLine("2,2,2,2");
CreatePic(4, 4);
}
this.serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(this.DataReceivedHandler);
}
but the problem is then I'm in the While loop I cant press any other Button in my program so it is not possible to stop. I have no idea how to stop it ?
I tried to press a button who set the RunReadCamAuto to false and Console.ReadKey()
I'm Using:
c# Form App
MS VS 2010
You cannot expect user interface to work while the main thread is busy doing some work in a loop. Use BackgroundWorker object to fire desired loop in it - it's automatically invoked on other thread and from your main thread you can easily send the message to stop its work.
You need to assign your method to BackgroundWorker's DoWork event and then from your form just call myBackgroundWorker.RunWorkerAsync(). Then by calling myBackgroundWorker.CancelAsync() you will change its CancellationPending property to true, which you can be constantly checking in your loop to break execution.
Please see here.
I have a gui. When I press a button my gui interacts with a software. It takes some seconds. During this time I want a dialog box, pop up or some thing like that to appear infront of my gui which tells the user to wait (with a message). When interaction of gui with software finishes the pop up automatically closes and user can again normally interact with gui.
Is there any way to do that ?
The trick is to spin off a thread so as not to tie up the UI thread. This is typically achieved via a BackgroundWorker.
There's a walkthrough for setting all this up on codeplex. The loading form closes when the backgroundworker is complete.
Here is briefly how it can be done using the BackgroundWorker component.
Put a BackgroundWorker onto your Form, then in the button's Click handler show your popup indicator Form above the current form, and start your worker with its RunWorkerAsync method. Handle the workers DoWork event, and it the handler, run the long running task. Also handle the worker's completed event (not sure now how it's called exactly), and in that hide your popup form. You can track the operation result in the DoWork event eventargs (Result property), and also you can catch any exceptions during the long running task with the completed event eventarg's Error peroperty. The operation progress can be reported in the DoWork handler with the worker's ReportProgress method, and it can be catched in the GUI with the worker's corresponding event.
You could also set mouse cursor to wait before long running operation
this.Cursor = Cursors.WaitCursor;
and than back to normal, then it's finished
this.Cursor = Cursors.Default;
I have a modal dialog with a cancel button only which pops up when the user clicks on a button. Aftre the modal dialog pops up, I would like to start a long process which monitors external event. If the event happens, then the dialog will be closed automatically. The user can cancel the monitoring process by clicking the cancel button.
I assigned the process start to the Shown event
private void ProceedForm_Shown(object sender, System.EventArgs e)
{
controller.StartSwiping();
}
The process itself is a loop
public void StartSwiping()
{
Status status;
do
{
status = CallForFeedback();
} while (status == Status.Pending);
form.DialogResult = DialogResult.OK;
form.Close();
}
The process starts fine, but the dialog does not pop up, so the user can non cancel the process. I also tried to assign the start to the Load event, but nothing changed.
Is there any way to Show the dialog and after that start the process?
Thanks
Your problem is that you are doing everything in the UI thread. You need to put you status monitoring loop in a separate thread so that the UI thread can remain responsive.
There are several ways you can do this, but one easy place to start is with the BackgroundWorker class
Use a Task to do your LongRunning events:
CancellationTokenSource _cancelationTokenSource = new CancellationTokenSource();
new Task(() =>
{
//Do LongRunning task
}, _cancelationTokenSource.Token, TaskCreationOptions.LongRunning).Start();
Use the _cancelationTokenSource to cancel the task when needed.
I would move the long running code onto a background thread as you are blocking the UI thread, which is why the UI never displays.
Use a background worker class for the controller functionality http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
When the work is completed on the background worker (i.e. the event is received) then you can use the following mechanism to callback onto the UI thread:
http://msdn.microsoft.com/en-us/library/ms171728(v=vs.80).aspx
Note: the article says you can turn off the crossthreadexception this would be considered bad practice, instead handle it the correct way using the InvokeRequired check and then invoke method on the windows form.
Others have suggested using a BackgroundWorker, or some other sort of background thread. While in many cases this is appropriate here, there is likely an even better solution. You're not just doing some long running task, you're waiting for something to happen. Rather than constantly polling...whatever it is, you should be using events. There should be an event that is triggered when you are done, and you should subscribe to that event to do whatever you need to do (i.e. close the dialog) when the correct conditions are met.
I have a form that appears as shown in the attached image. I have two parts of the form that concern this question: the TabControl, and the Panel, as shown in the image. It should be noted that the panel is NOT within the TabControl.
My situation is that I have a thread that executes continuously when the button, displayed in melt-your-eyes green in the Panel, is clicked. The thread polls the device which I'm interfacing with and updates the controls in the "Status" GroupBox at the bottom of the TabControl. When the user clicks on a control in the TabControl (tabControl_Enter event), I trigger a ManualResetEvent which lets the thread finish its iteration so that I can perform the IO required by the clicked control. The code to to suspend the thread is as follows:
private void StopSynchThread()
{
synchWaitHandle.Reset();
//various UI changes
}
private void updateSynchStat()
{
while (true)
{
synchWaitHandle.WaitOne();
try
{
updateSynch();
}
}
What I would like to do is then restart the thread automatically, instead of by button press, as is currently done. What I'm trying to do is avoid having to restart the thread by conditionally calling StartSynchThread() within each of the "bazillion" UI event handlers. StartSynchThread() is defined as:
private void StartSynchThread()
{
synchWaitHandle.Set();
}
Is there a precedent or decent paradigm for handling this? Without any concept of how to do so, I was thinking that I could alter my function that performs the IO with the device to generate an event after it gets a response from the device, but that seems inelegant.
Any ideas? I appreciate your insights. Thanks.
If you really can fire it off with a simple button click, you ought to be able to just put a timer on the form that will periodically check for the right conditions and then "push" the button (call synchWaitHandle.Set();) automatically.