I am having a very difficult time trying to debug/fix an application.
Briefly:
- I created a "wizard" type app that starts with the user taking a photograph (using the common dialog for photos)
If the user tries to use the text input window (SIP) (the little keyboard input window) after a photo is taken the event loop seems to hang - the event is not processed or is delayed for a while.
If the user does not take a picture the SIP keyboard works great.
This only happens on some of my devices. Specifically it is not a problem on an MC65 but is a problem on an ES400.
It appears that the app's event loop gets screwed up with the way I am displaying forms and taking photos.
If created a simple test app with single form containing a button (Event handler takes a photo) and a text box that accepts input. That works fine. But it is only a single form app that does nothing else.
When I combine the photo taking with my form displaying (making a "wizard" ) things go badly.
I wonder what kind of event loop should I be running?
Essentially the user takes a photo then goes through some forms (I hide one form and show another when they click the "next" button.)
The Form.Show is called from the main form after a picture is taken and then I have something like:
while(UserNotFinished)
{
Application.DoEvents()
}
Where UserNotFinished is a flag set from my wizard/forms after the "submit" button is pressed.
I will be happy to provide more code but not sure what would be useful.
I am new to C# and CF development (lots of years of C++/Win32)
The real confusing part is that this works on one device but not on another. In fact, the device hangs completely. It ends the activesync connection and sometimes I have to hard reset by removing the battery.
I think your problem stems from the while(true) { DoEvents(); } and perhaps how you are trying to go between forms. The only time I've used the DoEvents() method is when I'm already in the scope of a windows event and I need to be sure something in the message queue is processed so screen updates are correct. I'd suggest making a controller class to manage the screen flow for your wizard. You can control the screen flow by either using ShowDialog() and execute the flow control directly in the scope of a single call, or you'll have to use Show() and an asynchronous mechanism such as subscribing to and handling specific form and control events in the controller class. Also saw the comment about introducing another thread, beware that Forms belong to the thread they were created in and you must Invoke(...) all Form members in the context of the creating thread.
Hmm. Very strange
I started a new thread and basically call Application.DoEvents() in in as well and it seems to fix the problem...
I don't know why the
while(true)
{
DoEvents()
}
in the main thread doesn't work.
Related
I am trying to detect the Idle time in a Windows Mobile application and show a Screen lock after this inactive period. This link http://blog.opennetcf.com/ctacke/2009/05/19/DetectingApplicationIdle.aspx gives a hint but I found that this works only for a single form.
How can this same code be used across an application with multiple forms. I tried implementing this code after the InitializeComponent() for each form and used the Reset() function in the form Activate and GotFocus event so that the timer is reset after the user closes the screen lock by entering a PIN number. But this does not seem to work for multiple forms and the timer is not reset but it keeps firing every minute. Even if I am working on the application the event fires up every 1 minute (as per the sample code) and this is not correct.
Can anyone suggest how to use this functionality across the entire application.
Thanks in advance for any solution.
We need to see your code to know what's wrong, but the method proposed in that blog entry uses an IMessageFilter implementation. That hooks into the Windows message pump, which is application-wide not a single-Form system. I use the exact same technique for application-wide idle detection in a couple of solutions and it works well.
My guess is that you have a scope issue with the IMessageFilter instance you're using. If you create it as a Form-level variable (like the sample in that blog does), when close the Form that the filter is disposed of and will no longer work. If you have multiple Forms, you need to put it somewhere else in the Model so it survives as long as the app is up.
What about utilizing GetIdleTime ? Seems like this, paired with a timer that wakes peroidically to check it, could detect system idle and allow you to show the screen lock.
Using the CoreScanner Driver provided by Motorola, I'm trying to write a small winforms application that uses a barcode scanner. I'm able to interact with the scanner just fine, and properly register a call back for the OnBarcodeEvent(). In this callback, I have a Dialog that opens and displays a screen that the user needs to fill in. Shortly after the dialog is opened (using Show()), the program hangs. If I use ShowDialog(), the dialog works, but the dialog is blocking the OnBarcodeEvent event.
My guess to what is happening, is that since the dialog is getting created on the event thread, there is a race condition occurring when using Show(). Since Show() is non-blocking, the thread continues on after displaying the dialog and then dies out. Meanwhile my dialog just lost it's parent and locks up? Like i said... my best guess.
How can I remedy the situation? That is, How do I write my dialog so that it can be created within a thread not hang?
In the event, you should launch a different thread that will create your dialog form and show the form on it. You need to block this thread till form is visible - this is possible either by ShowDialog or alternately use one of Application.Run overload.
Yet another option would be to show the form on the UI thread (i.e. main application thread) - to do that, you need to call Invoke method on your main form from the event code. The invoke call should take the delegate that will show your dialog form non modally.
I have some experience with Motorola/Symbol Handheld-Devices (MC9090) and I guess the SDK will be similar.
It's hard to say without seeing the code, but my guesses:
your common not-UI thread problem - so make sure you open your dialog using UI thread
the native Motorola-driver is crashing - no kidding, this happened a lot to me - in my case (compact-framework on a WinCE device) this would not freeze the program but the scanner will not work/receive any messages before restarting the device
In order to fix this you should seperate the showing/handling of user-dialog away from the event and make sure you call this on the UI-thread (Control.InvokeRequired / Control.Invoke).
I have tried using this code sample:
private void DoShortRunningTask()
{
using (new StWaitCursor())
{
Thread.Sleep(5000); // 5 sec delay.
.. do some work ..
}
}
From: http://www.codeproject.com/KB/cpp/WaitCursor.aspx
But it did not do anything for me, since I did not have a main form. I do not need a main form. My C# project type is Windows Application, but the only GUI it shows if any is error or success messages dialogs. Is there a way for me to fake the existence of a WinForm (so that it exists but is not visible)? Would the mouse cursor have to be over it in order to show up?
I don't think it would be good practice just to change the cursor when it's not in your UI. You wouldn't want another program messing with the cursor in your UI. If you just want to show that your application is running, have you thought of using a tray app. These are relatively simple to create.
Here's an example I just googled:
http://alanbondo.wordpress.com/2008/06/22/creating-a-system-tray-app-with-c/
You can also show speech bubble messages as your run progresses etc, if you want to let the user know things are happening.
I do not need a main form
Yes, you do. Any UI interaction needs a form, sorry.
way for me to fake the existence of a WinForm (so that it exists but is not visible)?
How is that faking?
Make a form, make it invisible (transaprent - check all the properties on the form class and you will find it) and finished ;) Standard approach. Also tell it not to show up in the forms collection in the bottom of the screen and minimize it and you are finished. nothing fake here.
TomTom++
Are you just wanting to change the current cursor?
Try this
http://www.csharp-examples.net/hourglass-wait-cursor/
this is my first post. I have a huge problem which make me headaches. I have an app uses WinForms, a TTS (Text-To-Speech) voice and custom-buttons with states.
In my 1st form -main- when I click a button, the app opens a 2nd form above the 1st. Ok.
When I close the 2nd form trough a button, I tell the TTS say something and the form closed itself, viewing again the 1st form. Ok.
The problem starts when I click two times in the button on the 2nd form: the TTS says something, the button closes and the 'second click' is still in the click buffer (or somewhere) and it makes click in the 1st form (which appears 4 seconds later when I hit the button for the first time).
I am using the voice in a Sync mode; if I use the voice in an Async mode, the application ends wit h a nice exception.
If I click three or four times in the 2nd form, the other clicks still remains in buffer and clicks in the 1st form all the times.
I tried to (1) delete the DoubleClick event, (2) delete the event associated to the button and (3) hide the button which is clicked automatically when I return from the 2nd form, (4) hide the 1st form before create the 2nd and restore when it finishes.
Suggestions?
Thanks!
PD: I'm sorry by my English :S
PD2: I've uploaded a very simple example of what happens.
EDIT 2
Having looked at the code I understand the issue you're having now. The reason button clicks are being stacked up is when you call Speak within TTS the application locks up while it waits for the function to finish. Any presses in that time are stacked up until the application is free again to process them, you then close the form instanly before the messages are handled and these are then dealt with in the first form.
I've come up with a few solutions which could work for you:
Use only the SpeakAsync command within your TTS class and introduce a Waiting system where you wait for the speech to finish before doing anything. This will free the application and won't cause the mouse click events to stack up.
After you trigger a Speak command you could access the Windows message list and clear all the mouse click events that occurred before the process finished. Unfortunately, I'm not sure how you'd implement this as I've not done this before. I think you need to overwrite the WndProc function but again I'm not sure. This might be also be a bit dangerous as you may end up clearing a perfectly valid or important system message by mistake. Sorry can't provide any more help on that one.
Implement a background worker in your second form which will process the Speak commands seperately on a background thread. This again will free the application so the mouse click events won't stack up. I've modified your sample project and zipped it up for you to take a look. If you want I can explain further but essentially it does the following:
Form 2 loads and creates a background worker.
Worker_DoWork and Worker_WorkComplete delegates are created and set in the background worker. These functions are called when the worker is started and after the worker has finished.
Form 2 triggers the background worker to start. The background worker then sits in an infinite loop waiting for commands to process.
When the "Hello" button is pressed this sets a SayHello boolean to true, the worker spots this, carrys out the appropriate speak function and then resets the boolean ready for the next press.
When the "Close" button is pressed a CancelASync request is called in the background worker.
CancelASync interupts the BackgroundWorker's main loop (CancellationPending becomes true). The appropriate speak command is sent and the cancel property of the DoWorkEventArgs is set to true before breaking out of the BackgroundWorker's main loop.
Breaking out of the main loop causes Worker_WorkComplete to be called where the form is then closed.
I hope you can follow the example (linked below) and I've explained it well enough here. I prefer this solution as its quite extendable, you can add more conditions within the main worker thread for example.
Like I said, if you have any questions please ask and I'll try help as much as possible.
Hope this helps.
Example Link: http://www.mediafire.com/?2mf1yahto50ljs6
Use a boolean flag to track whether the form is in a state that accepts the click.
IE - when you open the 2nd form, 'boolean canPlaySound = true;' When the button click event fires, only play the sound if canPlaySound is true (and set it to false before playing the sound).
The next click will be ignored because canPlaySound = false. You won't play the sound.
I have this massive nested loop scenario that is calling the DB and making HTTP requests to Basecamp API. At first it was a web app but it took much time to run the app so the user (billing department) would often quit out early or complain because it would take so long with no feedback and no way to cancel it. I wanted to make it more responsive and give it a Cancel button as well as a real time log, I also wanted to make it more controllable. I put it in forms so they could have control of every instance of it and have a cancel button and a real time log.
However when I hooked it all up with form buttons, multi-line text box to replace the response and error log, I cannot get anything to work! I added checks in the loop to break out if Cancel becomes pressed. However I can't even click cancel and the multiline TextBox will not live update when I .Text.Insert and then .Update() it. The whole app just sits there and spins... How do I get it to be responsive, accept button clicks during looping, and live update the multi-line TextBox?
NOTE: The thing compiles fine and I can step through it and it writes to a log file just fine so I can tell it's working after the fact that my form freezes up by looking at that log file.
Here is the code I am trying to update the multi-line TextBox with:
TimeSyncLog.Text.Insert(TimeSyncLog.Text.Length, "(((" + clientCode + ")))\n");
And here is the code for my loop breakout:
if(CancelPressed)
{
TimeSyncLog.Text.Insert(TimeSyncLog.Text.Length,"\n\nSYNC STOPPED BY USER.");
break;
}
But I can never click the Cancel button to toggle that boolean because the window says 'Not Responding'...
You shouldn't do any time consuming business logic on the UI thread.
you can use the BackgroundWorker class for those kind of things. it also support cancellation and progress report.
You can read about it here.
The UI thread should have only UI related changes in it. Semi-irrelevant to your question, there's an awesome threading tutorial here.
BackgroundWorker is a great class that uses the thread pool, though there are many options and things to consider when threading. If you want to cancel the thread, maybe nest an event in the GUI class so that the worker can subscribe to it, to handle the event of the 'Cancel' button being pressed. Perhaps that isn't the most efficient way, but I'm sure someone else around here can recommend a few more alternative routes. Hope this helps.