I have an issue very similar to DataGridView refresh causes "Not Responding" application (but only when not in Visual Studio)
While loading my data to my Winforms app form, I temporary disable a panel filling the form and containing all the controls, and I enable it back when done.
As in the example, I work with BackgroundWorker to load data and use thread-safe bgWorkerSend_ProgressChanged or bgWorkerSend_RunWorkerCompleted to interact with the UI.
I also have a Windows Forms timer that refreshes in the same way the form after 5 minutes of idle time.
What is weird, is that at the end of the init load, the panel is enabled back correctly, while in the latter refresh, the application enters "Not Responding" mode, and remains there forever. Furthermore, this only happens when I execute directly the application. If executed from Visual Studio, it works correctly both at initial load and at refresh.
private void _bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (e.ProgressPercentage == 100)
{
// re-enable panel
panel1.Enabled = true;
// the below is never reached !!?
AnyInstruction();
}
}
Narrowing down the issue, it showed that the problem was because the code inside BackgroundWorker thread was filling a DataSet that has been instantiated earlier in the main thread.
By moving the instantiation into the BackgroundWorker thread instead, resolved the issue, and panel1.Enabled = true; is now executed correctly in _bw_ProgressChanged.
Related
With Winform Form Window (FixedDialog with toolbars) providing options to install and uninstall the application. (Windows exe application)
When a user clicks on the button to install/uninstall, the window can neither be moved nor minimized.
i.e. until the event raised for activity is not completed, it's stuck and not able to perform any action on the form window.
Events are added as below which does independent work.
in form1.designer.cs
private void InitializeComponent(string defaultPath)
{
//Other steps
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.InstallButton.Click += new System.EventHandler(this.InstallButton_Click);
this.UnInstallButton.Click += new System.EventHandler(this.UnInstallButton_Click);
}
Eg. The function InstallButton_Click has multiple steps for installation which copies files and does other work which takes around half a minute. During this time it doesn't allow to move or minimize the window.
In form.cs
private void InstallButton_Click(object sender, EventArgs e)
{
//Multiple steps for installation
//takes around 20-30 seconds to complete
}
The issue is similar to what is mentioned here, but don't see an acceptable answer there.
Is there a way to allow the user to minimize or move the window?
Here multiple approaches are available.
As the code involved some steps updating the GUI controls back, couldn't use the solutions directly.
As almost all solutions are based asynchronous principle, it used to throw an error, Cross-thread operation not valid: Control 'InstallButton' accessed from a thread other than the thread it was created on.
To avoid it segregated steps involving GUI control access and executed them sequentially while as remaining independent code was run asynchronously using Task.Run() method.
It has ignorable execution time for GI
//Logic to update control
Task.Run(()=>
{
//Remaining logic
});
Some info:
C#
Winforms project in visual studio 2012
.Net framework 4.5
Windows 8.1 OS x64
I am having the strangest bug!
Whenever i use:
private void Main_Load(object sender, EventArgs e)
{
TestForm form = new TestForm();
form.ShowDialog();
}
TestForm is just a stadard form with no controls added.
It will stop the main thread as it should! But instead of waiting for input, it will spawn a new "form" ever 0.5 sec aprox... i took a new solution and tried, and there it worked fine, but in the app im currently working on, it does this when ever it is run somewhere inside or from this form.
Placing the same form code inside a BackGroundWorker, then it works fine.
ONLY inside the main UI form i have, where this error occurs..
Using Show() works as normal, only 1 form opens, but does not work with dialog result :-/
I have no idea why and have never seen this before??
please help.
EDIT:
I did as Roy Dictus suggested, and placed a break point.
This is in my LauncherFrom that load Main:
private void timerHide_Tick(object sender, EventArgs e)
{
this.Hide();
// Open main form IF true else open hidden
var f = new a.Views.Main();
if (Properties.Settings.Default.StartHidden)
{
f.Opacity = 0;
f.Show();
f.Hide();
f.Opacity = 1;
}
else
{
f.Show();
}
// Stop timer
timerHide.Stop();
}
And it looks like timerHide.Stop(); is never being called.
I have used this many times before, and i have a few more ShowDialog() calls that work fine..
So why does this not work for only SOME of the ShowDialog();??
If i remove TestForm.ShowDialog(); from Main_Load() it calls timerHide.Stop(); just fine.
Your code never reaches tiemrHide.Stop(). That's because you show a modal dialog which runs its own message pump. And so your timer fires again and again.
Here's how it goes:
The timer event timerHide_Tick fires, and creates a new main form instance.
The new main form shows a modal dialog in Main_Load.
The modal dialog runs a message pump.
The timer event fires again.
Goto 1.
You need to call Stop() at the very start of timerHide_Tick.
Our application uses an animation to fade out a message window when it's closed. To do this, we override OnClosing, and if we haven't completed our animation, we cancel the close and start the animation. When the animation completes, we close the window. This seems to be a fairly common pattern based on what I've seen online, since Closing and Closed aren't routable events.
The problem is, we occasionally see a window get "stuck" - the animation doesn't seem to occur, so the "finished" flag never gets set and the window just sits there, canceling any close events. Sometimes, the animation eventually kicks off and the window closes, but other times it seems like its permanently stuck (though obviously you can't tell for sure...halting problem and all that...).
Does anyone have any thoughts as to why the Storyboard won't get kicked off even after calling Begin()? Without having been able to dig in really deep into the Storyboard code/data structures, it feels like it's waiting for something to happen before it actually kicks off, that never happens.
Here are some of the possibilities that I've ruled out so far:
incorrect threading (all windows, animations, storyboard, etc. are created/handled/accessed on the GUI thread)
GUI thread blocked (clicking the X still fires the Closing event, and the GUI thread responds to events in other windows, system tray, etc.)
GUI thread busy (we're only doing UI work on the GUI thread, and we generally only have one window open and at most one "close" animation running at a time)
That said, here are some things that might be contributing:
Windows can close each other (in some cases if one is already open, the new one will close the existing one)
We also have a "fade in" animation bound to the Loaded event via XAML, but that seems to complete correctly.
We recently removed our "main" UI window, so the application's main window is now a dummy hidden window.
I suspect that last one most strongly because it was added most recently, and this behavior was never reported/noticed before that change (though I can't say definitively it never happened before that change). But other GUI/window-related events still all work, and the fade-out animation logic works most of the time.
Finally, here's the meat of our code for doing the closing animation:
public class MyWindow : Window {
private bool _storyBoardCompleted;
private Storyboard _closingStoryBoard;
protected Storyboard GetClosingStoryBoard()
{
Grid mainGrid = (Grid)FindName("MainGrid");
DoubleAnimation closingAnimation = new DoubleAnimation();
closingAnimation.From = 1;
closingAnimation.To = 0;
closingAnimation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
Storyboard.SetTarget(closingAnimation, mainGrid);
Storyboard.SetTargetProperty(closingAnimation, new PropertyPath(OpacityProperty));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(closingAnimation);
storyboard.Completed += StoryboardCompleted;
return storyboard;
}
private void StoryboardCompleted(object sender, EventArgs e)
{
_storyBoardCompleted = true;
Close();
}
protected override void OnClosing(CancelEventArgs e)
{
if (_closingStoryBoard == null)
{
_closingStoryBoard = GetClosingStoryBoard();
_closingStoryBoard.Begin();
}
if (!_storyBoardCompleted)
{
e.Cancel = true;
}
}
}
EDIT:
The issue seems to pop up whenever we open two of these windows very close together in time, and close the first before showing the second. Essentially:
window1.Show()
window1.Close()
window2.Show()
At this point, if we try to close window2, it will cancel the close as in the code above, but the animation won't begin (hence the problem). If we later on call window2.Close() followed closely by window3.Show() (i.e. show a third window), then window2's animation finishes and the window closes - but then window3 is stuck in the same state. So the behavior almost seems to get "passed on" from window to window once we are in this state.
EDIT:
I've ruled out another possibility - I was wondering whether the "fade-in" storyboard of the second window was somehow conflicting with the "fade-out" storyboard of the first, and somehow affecting the second window's fade-out. But the problem occurs even after removing the fade-in storyboard.
Furthermore, the problem goes away entirely if I replace the fade-out storyboard with just a half-second dispatch timer (i.e. just a delayed close, no animation). Just a sanity check that it definitely has something to do with the animation...
Did you ever try adding parameters to the Begin method:
_closingStoryBoard.Begin(this);
I never could quite pin down specifically why this was happening, but it seemed to be related to the fact that I was showing the second window while the first one was still animating. I still don't understand why this caused problems, but I was able to work around it by waiting for the first one to close completely before showing the second (basically hooking onto the first window's Closed event).
Would still love to know why this behaves this way, in case the workaround of "wait for the first window to close" ever stops being sufficient...
I have a form in a Windows form application that I want to display on top of a main form, close it, and then immediately show a dialog box using MessageBox.Show(). But the first form is still showing when the message box is shown, and it does not disappear until I click OK on the message box. I tried waiting to show the message box in an event handler for the form's VisibleChanged event and even calling Refresh() on both the form and the main form. Is there a way I can determine when the first form has fully disappeared before displaying the message box?
Edit:
Here is some code that demonstrates how the forms are being shown.
static class Program
{
// The main form is shown like this:
static void Main()
{
Application.Run(new MainForm());
}
}
public class Class1
{
// _modalForm is the first form that is displayed that won't fully go away
// when it is closed.
ModalForm _modalForm;
BackgroundWorker _worker;
public Class1()
{
_modalForm = new ModalForm();
_worker = new BackGroundWorker();
_worker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted
}
public void Method1()
{
_worker.RunWorkerAsync();
// The first form is shown.
_modalForm.ShowDialog();
}
// This code runs in the UI thread.
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_modalForm.VisibleChanged += new EventHandler(_modalForm_visibleChanged);
_modalForm.Close();
}
void _modalForm_visibleChanged(object sender, EventArgs e)
{
// When the message box is shown, the other form is still visible
// and remains so until I click OK.
MessageBox.Show("The other form was just closed.");
// Note: I originally tried to use the FormClosed event instead of
// VisibleChanged. Then I tried Deactivate, in attempt to use an event
// that occurred later thinking that might do the trick. VisibleChanged
// is the latest event that I found.
//
}
I'll guess that you are running your code on Windows XP or Vista/Win7 with Aero turned off. Closing a form does not make the pixels on the screen disappear instantly. The Windows window manager sees that the window for the form got destroyed and that this revealed parts of other windows underneath it. It will deliver a WM_PAINT message to let them know that they need to repaint the parts of the window that got revealed.
This will not work properly if one or more of those windows isn't actively pumping a message loop. They can't see the WM_PAINT message. They won't repaint themselves, the pixels of the closed form will remain on the screen.
Find out why these windows are not responding. Hopefully it is your window and the debugger can show you what the UI thread is doing. Make sure it isn't blocking on something or stuck in a loop.
After seeing the edit: there's indeed blocking going on, of a different kind. The MessageBox.Show() call is modal, it prevents the VisibleChanged event from completing. That delays the closing of the form.
Use System.Diagnostics.Debug.WriteLine() or Console.WriteLine() to get diagnostics in a Window Forms app. You'll see it in the Output window. Or simply use a debugger breakpoint.
The Form.FormClosed event is raised when the form completes closing. At this point, all Form.FormClosing event handlers have been run, and none of them canceled the close.
Form.FormClosed replaced Form.Closed (which is deprecated) in the .NET 2.0 framework.
Form.Closed Event
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed(VS.71).aspx
I've one MainForm window and from that user can press 3 buttons. Each of the button starts new Form in which user can do anything he likes (like time consuming database calls etc). So i decided to put each of the forms in it's own threads:
private Thread subThreadForRaportyKlienta;
private Thread subThreadForGeneratorPrzelewow;
private Thread subThreadForRaporty;
private void pokazOplatyGlobalne() {
ZarzadzajOplatamiGlobalneDzp varGui = new ZarzadzajOplatamiGlobalneDzp();
varGui.ShowDialog();
}
private void pokazRaportyKlienta() {
RaportyDzpKlient varGui = new RaportyDzpKlient();
varGui.ShowDialog();
}
private void pokazRaportyWewnetrzne() {
RaportyDzp varGui = new RaportyDzp();
varGui.ShowDialog();
}
private void pokazGeneratorPrzelewow() {
ZarzadzajPrzelewamiDzp varGui = new ZarzadzajPrzelewamiDzp();
varGui.ShowDialog();
}
private void toolStripMenuGeneratorPrzelewow_Click(object sender, EventArgs e) {
if (subThreadForGeneratorPrzelewow == null || subThreadForGeneratorPrzelewow.IsAlive == false) {
subThreadForGeneratorPrzelewow = new Thread(pokazGeneratorPrzelewow);
subThreadForGeneratorPrzelewow.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportow_Click(object sender, EventArgs e) {
if (subThreadForRaporty == null || subThreadForRaporty.IsAlive == false) {
subThreadForRaporty = new Thread(pokazRaportyWewnetrzne);
subThreadForRaporty.Start();
} else {
}
}
private void toolStripMenuGeneratorRaportowDlaKlienta_Click(object sender, EventArgs e)
{
if (subThreadForRaportyKlienta == null || subThreadForRaportyKlienta.IsAlive == false) {
subThreadForRaportyKlienta = new Thread(pokazRaportyKlienta);
subThreadForRaportyKlienta.Start();
} else {
}
}
I've got couple of questions and i hope someone could explain them:
When i use Show() instead of ShowDialog() the windows just blink for a second and never shows. What's the actual difference between those two and why it happens?
When i use ShowDialog everything seems normal but i noticed not everything gets filled properly in one of the gui's (one listView stays blank even thou there are 3 simple add items in Form_Load(). I noticed this only in one GUI even thou on first sight everything works fine in two other gui's and i can execute multiple tasks inside those Forms updating those forms in background too (from inside the forms methods). Why would this one be diffrent?
What would be proper way of doing this? Tasks performed in each of those Forms can be time consuming and i would like to give user possibility to jump between those 4 windows without problem so he can execute what he likes.
The difference is with Modal and Modeless Windows Forms.
Modeless forms let you shift the
focus between the form and another
form without having to close the
initial form
Show() method is used for this purpose
Show() shows the new form, then returns. If this is all the thread is doing than the thread will exit, and that will destroy the form.
ShowDialog() shows the form, and then begins running a message pump, until the form is hidden or destroyed, ShowDialog() doesn't return, so your thread keeps running.
If You mean for these forms to each behave like a separate application window. then you could also use Application.Run() after form.Show() to run a message pump for the form on that thread. The drawback to doing it this way, is that when any one of your forms is closed, it might end up taking down the whole process because of the way WM_QUIT is handled.
But other than the way you would deal with closing down your application, Form.ShowDialog() is very much like Form.Show() followed by Application.Run(). The conditions that cause the message pump to exit are a bit different between these to, so you would choose one or the other mostly based on how you want to your application to handle closing one of your forms.
You should put the time-consuming tasks in their own BackgroundWorker threads. Keep all of the forms in the main thread.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
1: Show() is not blocking, that is it shows the window and then returns. Afterwards, the varGui variable goes out of scope and is finalized by the garbage collector => disappears.
2: You'd need to show the updating code to get a definite answer, but as you can only update the contents of a form when running in the thread that created the form. Doing it otherwise is unreliable, so is the usual culprit when form updates don't work. In a method of a form class, call:
if (InvokeRequired) {
.Invoke(..); // call back this same method on the right thread
} else {
// dowork
}
to manage the UI.
3: The proper way is what Jake wrote: use one thread for all GUI stuff and BackgroundWorker threads for, well, background work.