WaitDialogForm.ShowDialog() not processing other code - c#

Pretty new to DevExpress, my company is stuck using 9.3
I've got this very small snippet of code:
wait = new DevExpress.Utils.WaitDialogForm("Please wait...", "Performing SVN check");
wait.Visible = false;
wait.ShowDialog();
ParseSVNResults(CheckSVN());
wait.Close();
My WaitDialog displays, but the code never continues. I put a breakpoint on ParseSVNResults and when I run the code it gets to that line.
It works properly if I just call Show() instead of ShowDialog(), but that gives poor behavior should the user click outside of the Wait form. The application "whites out" like it's stopped responding and the mouse changes into that little rotating circle icon. Also the hour glass that the dialog form shows doesn't rotate. Stupid minor detail, but it looks like the whole application crashed to end users.

ShowDialog, by design, "blocks" the code until you close the dialog. That is the entire purpose.
The reason that Show() is causing everything to white out is that your work is happening in the UI thread. The proper way to handle this would be to move your work (ParseSVNResults) into a background thread, via something like BackgroundWorker or a Task.

Related

How to debug why a form can not obtain focus?

Using Visual Studio 2019, with an old C# Winforms .NET 4.6.2 application: I have a situation where my main form is acting as if it is being blocked by a modal:
Makes a beeping sound and flashes when clicking anywhere
Will not accept focus
Timer and serial communication Events are still triggering
No grey screen overlay, or message about the application ever becoming unresponsive
However, I can see no modal form, and using Application.OpenForms doesn't show any of the modals that I have created and have closed a few seconds previously.
I can successfully attach and debug remotely, that is how I know the timer ticks are still firing.
How / Where can I place a breakpoint to troubleshoot why a form will not receive focus / denies click events / thinks it is being blocked by a modal of some kind?
It is too difficult to create a minimal example because the backgroundWorker and showDialog code all seems to work properly in other locations, but the gist of what is happening looks like:
Application.Run (new FormA)
...
FormA.showDialog(new FormB)
...
FormB.showDialog(new FormC)
...
FormC.timer_tick() { ...still running... }
FormC.onReceive_data() { ...still running... }
FormC.button_click(){
...
showDialog()
...
showDialog()
...
important.showDialog() { backgroundWorker...database stuff }
...
showDialog()
...
}
(known completion : back to FormC event-loop)
It always gets to "known completion" just fine, important.showDialog() seems to work fine, pops up an animating dialog with no buttons, auto closes when backgroundWorker completes, closes itself and moves on to the next dialogs or exits button click fine.
But once back in FormC-Event-loop, the form will not receive any input, as if it is still blocked by some modal somewhere...
If I change to important.show() FormC will not have a problem, but now there is code in the click event running before database activity is finished...
I am more interested in debugging technique in this case as to how I can figure out what windows is doing as I try to click on FormC. What kind of debugging module symbols need to be loaded? Where can I breakpoint to see windows deciding whether a form can receive focus/input?
"something has gone wonky with the re-enabling mechanism" made me go through with a fine tooth comb and check how the dialog is being closed off, and I found the original problem:
FormC starts a backgroundWorker and then waits on important.showDialog()
Inside the RunWorkerCompleted() or a timer_tick : "important" was FormC.BeginInvoke() .closed() and .disposed() . But apparently the .dispose() can (but not always) happen on the wrong thread or at the wrong time and then the parent form can never be enabled again. .close() and nulling the formDialog reference allows the parent to get re-Enabled.
Out of interest, I am still wondering how you would go about debugging such a situation?

Showing Message for loading WPF

I have a WPF application that connects and disconnects to WiFi.
It takes around 2 seconds to complete the process. During that time, I want to show a simple waiting message on the top of my current window "Connecting.." or "Disconnecting...", which closes as soon is the process is complete.
What should I use?
MessageBox is not working because a) it has a button, and b) I can't just close it at my own will through code (I think).
When the Wi-Fi starts to connect, use:
MyWindow popup = new MyWindow();
popup.ShowDialog();
Where MyWindow is a small form containing information.
And when the Wi-Fi is connected, use:
popup.Close();
ShowDialog() prevents user interaction with the parent form.
You should do the long-running task that takes two seconds to complete on a background thread and show and close the window on the dispatcher thread, e.g.:
Window window = new Window()
{
WindowStyle = WindowStyle.None,
Content = new TextBlock { Text = "working..." }
};
Task.Run(() =>
{
//do something that might take a while here...
System.Threading.Thread.Sleep(2000);
}).ContinueWith(task => window.Close(),
CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
window.ShowDialog(); //Call .Show() instead if you don't want to block here until the task has finished.
For this sort of thing I use a busy "throbber" or "spinner" which is shown in a panel on top of the window. That just animates to show something is going on.
I bind the visibility of that to an "IsBusy" property in my window's viewmodel.
In a base viewmodel that inherits from, because this is a common requirement.
When I set Isbusy true, the spinner appears and animates.
When I set it False, the spinner disappears.
I also have an area where I show messages. These are animated so they appear and then fade out after a few seconds.
It's a bit much code to paste into a SO answer, but there's working code uses this approach here:
https://gallery.technet.microsoft.com/WPF-Entity-Framework-MVVM-78cdc204
Throbber is the usercontrol to look at.
This usually goes in a panel covers where the user would edit stuff - so they can't change data as it's being updated.
I also use IsBusy in the CanExecute predicate of commands to disable buttons etc as processing is done. Because notification isn't necessarilly instant I check inside all commands and exit if IsBusy is true. Commands set IsBusy true whilst they run.
For completeness and probably not directly relevant to Bella's question.
In some situations I want to just show the user that processing is happening but allow them to continue working. This happens a fair bit in the Map and Scenario editors of the game I'm working on.
For example, when you mouse over a commander there's a Spatial A* best route calculation happens between a commander his subordinates that can take in the order of 1 to 12 seconds. I don't want to block the user but I want to show something is going on in this instance.
I have a second mechanism with a less intrusive throbber I use for this. That appears next to my user notification message.

c# Label is "empty"/is a hole in the form

I have 2 windows. The main form and the Loading form. In the main form you send a request which will be executed. Because this takes some time, I made the Loading-form with a progress bar so that the user knows the program is working.
What I want to: The Loading-form should open itself when the process ist started and close itself when it's finished.
At the moment I have code that looks something like this:
Loading.Show();
Loading.MakeAStep(); //used for progressing the progress bar
//program is working
//finishes
Loading.Visible = false;
Loading.ResetProgress(); //Sets the value of the progress bar to 0
My problem is: The window with the progress bar opens, but there is also a label which shows "please wait". When the form opens, the progress bar works perfectly, but the label is just a hole (it really is you can look through it). When I use instead of visible = false form.Close, it works just fine with the label but I get an error when I try to start a progress in the same session.
What I want/need: Either a solution to the hole-problem, or an effective way to open and close a form several times during one session.
(Posted the solution on behalf of the question author).
The answer is in the comments: The UI blocks and I needed to Update the form with Loading.Update(); I put that between Show and MakeAStep.
As already mentioned by others, the problem is that you run your long running process in the UI thread. To avoid this, you should improve how the loading form receives the task and works on it:
The loading form should get the thing to run as a Task (maybe by a method Run(Task task). After getting this task the loading form can attach another action to it, what shall happen when the task is finished by using .ContinueWith() and simply closes itself when it reaches that point. After that it will Start() the task and call ShowDialog() on itself.

Pause button for a game c#

I just want to create a simple pause button, and perhaps another button to resume if necessary. I've been looking around and I mostly see Thread.Sleep(), which doesn't work for me because I want the pause to remain paused until the user desires.
Thread.Suspend() doesn't work because that is obsolete now.
I've also seen another solution of creating a second form, however, that doesn't seem to be working for me. Once that second form opens up, the entire program closes.
I'm not sure if this makes a difference, but my program currently uses two threads (main thread running form1 along with another thread). Ideally, everything needs to be paused.
The simpliest thing to do is to have some variable/property that the other thread can access.
Bool ShouldPause = false;
The other thread should have in it's game loop something like that :
while(true)
{
if(!ShouldPause)
{
UpdateGame();
}
Draw();
}
Then the game will proceed only when the ShouldPause variable is false.
I did it several times and it worked perfectly.
You don't want to pause the thread via some "Suspend" like functions because it will prevent from him to draw on the screen and would appear like it's not responding.
You can use Thread Signaling technique.
A good start is to take a look at ManualResetEvent Class

Why does Refresh() not do what DoEvents() does?

I am trying to understand a certain longstanding concept in Windows Forms re: UI programming; following code is from Chris Sells' Windows Forms Programming book (2nd Ed., 2006):
void ShowProgress(string pi, int totalDigits, int digitsSoFar) {
// Display progress in UI
this.resultsTextBox.Text = pi;
this.calcToolStripProgressBar.Maximum = totalDigits;
this.calcToolStripProgressBar.Value = digitsSoFar;
if( digitsSoFar == totalDigits ) {
// Reset UI
this.calcToolStripStatusLabel.Text = "Ready";
this.calcToolStripProgressBar.Visible = false;
}
// Force UI update to reflect calculation progress
this.Refresh();
}
This method is part of small sample application that has another long-running method which calculates Pi. Each time a cluster of digits are calculated, ShowProgress() is called to update the UI. As explained in the book, this code is the "wrong" way of doing things, and causes the UI to freeze when the application is minimized and then brought into the foreground again, causing the system to ask the application to repaint itself.
What I don't understand: Since this.Refresh() is being called repeatedly, why doesn't it process any system repaint event that is waiting for attention?
And a follow-up question: When I add Application.DoEvents() immediately following this.Refresh(), the freeze-up problem disappears. This is without having to resort to Invoke/BeginInvoke, etc. Any comments?
Basically, the reason for this is the way Windows handles messages - it does this in a synchronous way in an internal message loop.
The point is that there was a message that triggered your code. For example a button click. Your application is in the middle of handling the message. From within this handler, you force the refresh which puts another WM_PAINT in the message queue. When your handler finishes, the message loop will surely pick it up and dispatch, thus repainting the control. But your code is not finished, in fact it loops calling your ShowProgress, causing WM_PAINT being queued forever.
On the other hand, the DoEvents() causes an independent instance of the message loop to fire. It's fired from within your code which means that the call stack looks like this:
outer message loop -> your code -> inner message loop.
The inner message loop processes all pending messages, including the WM_PAINT (thus the control is redrawn) but it is dangerous - as it will dispatch all other pending messages, including button clicks, menu clicks or event closing your application with the X at the top-right corner. Unfortunately, there's no easy way to make the loop to process the WM_PAINT only which means that calling DoEvents() exposes your application to subtle potential problems involving unexpected user activity during the execution of your code which triggers the DoEvents.

Categories

Resources