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

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.

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.

Updating a form through another form in C#

I have a button in a form. When the button is clicked, the button click function is called. In the function at first another form (let's call it object form2 from class Form2) it is created with some objects including labels and progress bars (these objects are created through form2 constructor). Then form2.Show() is called. Then a while loop comes which by end of it some variables are updated. I use these variables to update several objects in form2. The problem is that the form objects are not shown rightly until the button click function is finished. For example instead of labels, white rectangles are shown. I tried using Thread.Sleep(1000) after my while to see if objects are shown rightly but it didn't have any effect on form2 shape. Then I used a MessageBox.Show() after my while and it worked surprisingly! Objects were shown correctly in form2.
I appreciate if anyone could say what is the problem and how I can solve it.
You're blocking the UI thread, thus preventing updates until you release the UI thread to continue handling other messages sent to it.
If you have long running CPU bound work, you should be offloading it to another background thread. If you have IO or other non-CPU bound work to do you should be doing it asynchronously, rather than synchronously blocking on it, so that the UI thread can continue processing other events.
If you do heavy work you really should do it in a background worker.
Meanwhile (to get it work) you can call Application.DoEvents which should give your controls "time" to update.
Taken from MSDN:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.doevents%28v=vs.110%29.aspx
foreach (string file in files )
{
System.IO.FileInfo fileInfo = new System.IO.FileInfo(file);
System.IO.FileStream fileStream = fileInfo.OpenRead();
pictureBox1.Image = System.Drawing.Image.FromStream(fileStream);
Application.DoEvents();
fileStream.Close();
// Call Sleep so the picture is briefly displayed,
//which will create a slide-show effect.
System.Threading.Thread.Sleep(2000);
}
If you are interested in more details, Hans has a good explanation: https://stackoverflow.com/a/5183623/2243584
One could always argue about the use of Application.DoEvents but as Hans stated ShowDialog uses it internally as well - thats the reason why your MessageBox example worked!

WaitDialogForm.ShowDialog() not processing other code

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.

Form Visiblity Problem

Form1.button_Click(...) {
// Show a dialog form, which runs a method <CheckBalance()> on it's OnLoad Event.
var modemDialog = new ModemDialog("COM25");
modemDialog.ShowDialog();
// the user can't see this dialog form until the method <CheckBalance()> terminates.
}
Is it possible to show first the dialog then run the specified method?
THanks.
That is correct and expected. Winforms UI is inherently single-threaded. Having a function call like "CheckBalance" in the form load event will prevent the form from showing until the form load event completes. Depending on the duration of the task, you have a number of options available to you:
If it's a fast task, compute it ahead of time before showing the form
If it's something the user may want to initiate, move it to a button on the new form, so it's only calculated on the request of the user
If it's a long running task that takes some time, you'll need to move it off in to another thread. Using a BackgroundWorker is recommended.
OnLoad occurs before the form is shown to allow you to initialise the form and variables and what not, which means it is synchronous. The form will not show until you return from that function.
If you want to asynchronously run the CheckBalance() method, then you can use a few techniques, such as utilising the Threading, ThreadPool or Tasks API to shift that work to a background thread, and returning immediately so that the form is shown.
Here is an example of using a Task to perform the same action, but asynchronously so that the form immediately shows:
Action<object> action = () => { CheckBalance(); };
new Task(action).Start();
Please note that if you access the UI thread, you'll need to beware of thread-safety and invocation.
The simple way to make sure your form is visible before CheckBalance is run is to use this code in the form load handler:
this.BeginInvoke((Action)(() => this.CheckBalance()));
This will push the execution of the CheckBalance method onto the UI thread message pump so will execute after all preceding UI code is complete.
Others are correct though that the UI will still be blocked as CheckBalance executes. You probably want to run it on a background thread to prevent this.

Categories

Resources