I created a very basic console app that executes some code behind the scenes. While it's doing this, it generates a custom message box (it's technically a Windows Form) that just displays one label telling the user to please wait. The issue is that the label NEVER is displayed (it's just a big white box where the label should be). I tried creating a dynamic label and putting it there, but this too does not work.
The form is shown in the following manner:
public void DoSomething()
{
MyForm form = new MyForm();
form.Show();
try {
// Execute other logic
} finally { form.Close(); }
}
I'm guessing it has something to do with calling Show(), but I'm not positive. I put in logging and see that it's going through the constructor, generating the dynamic label (which is added to the form via Controls.Add(myLabel)), but it still does not show any label.
A Form requires the message pump to be started in order to display correctly. This requires calling Application.Run. Unfortunately, this will block the current thread until the "application" is complete, so won't be able to just "drop in" to your code.
That being said, if you're developing an application which requires windows, you should consider making it a true windows application instead of a console application. You could just hide the main form, if required, and that will allow code like yours above to work properly.
Related
This may seem like a rather obvious and extremely newcomer question (and it is), but I've merely been attempting to transition between multiple forms in C# Winforms and somehow managed to encounter numerous complications:
To begin, I used the obvious:
frm_hub hub = new frm_hub();
hub.Show();
However, each time this code run, a new instance of frm_hub was created and using hub.Close(); would not work because it was not closing the same new instance of frm_hub
Is a way to close the same instance of a form from a different form - say with a global variable? Or is there some way to integrate a Close(); so the entire program continues to function and new form displays?
As a possible solution to the above issue, I tried to store the same form as a variable:
frm_hub hub = new frm_hub();
private void OpenForm()
{
hub.Show()
}
However the runtime error: 'System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.' was showing when I attempted to use this same tactic of storing the form as a variable in the two forms.
Why is this error occurring? And is there any way I can overcome it?
Finally, during some reading to counter this issue I discovered the use of controls and panels, and in this way, I could create an interface that opens different the different forms in a panel
However, my attempt of this required the use of anchors to get the form to display remotely true to the Designer appearance
If I do not require the form to be resizable, how can use panels to display a different form and at that in a way that displays the design elements how I have them positioned
Apologies again for my beginner understanding and use of terminology, feel free to seek clarification for crucial details I probably haven't included haha,
Thank you!
I used the following, not sure it's best practice. I used a button ShowFrmHubButton and disabled it when the window is already shown.
In my example the second form is modal, and you can't use the first window as long as the second is displayed.
ShowFrmHubButton.IsEnabled = false;
var frmHubWindow = new frm_hub ()
{
Owner = this
};
frmHubWindow.ShowDialog();
ShowFrmHubButton.IsEnabled = true;
Then, when you close\cancel the second form use this.Close();
I want to display a MessageBox that is modal to just a single form, and allows other top level windows on the thread to remain active. WinForms disables all windows on the current thread, whether displaying a custom modal form or using the MessageBox class.
I've tried a number of different approaches to solving the problem, including re-enabling any other top level windows (using the Win32 EnableWindow function) and p/invoking the native MessageBox function. Both of these approaches work, but leave keyboard shortcuts inoperable, including tab to move between controls, escape to cancel an open menu and most importantly menu shortcut keys.
I can make menu shortcut keys work by installing a keyboard hook when I display the MessageBox and then directly calling ProcessCmdKey on the active form, but other keyboard shortcuts still don't work. I guess I could press on and add more hacks to make these other cases work, but I was wondering if there was a better way.
Note, this is not about being non-blocking, but about not disabling all windows on the current thread. It happens that the solution may be similar, however.
The basic problem you are battling here is that MessageBox.Show() pumps its own message loop to make itself modal. This message loop is built into Windows and is thoroughly unaware of what the Winforms message loop looks like. So anything special that Winforms does in its message loop just won't happen when you use MessageBox. Which is keyboard handling: detecting mnemonics, implementing navigation and calling methods like ProcessCmdKey() so that a form can implement its own shortcut keystrokes. Not normally a problem since it is supposed to be modal and ignore user input.
The only practical way to revive this is to display the message box on its own thread. This is formally allowed in the winapi, the owner of a window can be a window owned by another thread. But that's a rule that Microsoft did not implement when they added the code to .NET 2.0 that detects threading mistakes. Working around that code requires an IWin32Window as the message box owner that is not also a Control.
Add a new class to your project and paste this code:
using System;
using System.Threading;
using System.Windows.Forms;
public class NonModalMessageBox : IWin32Window {
public NonModalMessageBox(Form owner, Action<IWin32Window> display) {
this.handle = owner.Handle;
var t = new Thread(new ThreadStart(() => display(this)));
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
public IntPtr Handle {
get { return handle; }
}
private IntPtr handle;
}
And use it like this:
new NonModalMessageBox(this, (owner) => {
MessageBox.Show(owner, "Testing", "Non-modal");
});
Where this the Form object that should be disabled while the message box is displayed. There's little I can do to make you feel better about this hack, if the FUD is too overpowering then you really do need to re-implement MessageBox with your own Form class so you can use Show() instead of ShowDialog(). It has been done.
You could pass a reference to the Form, set Enabled property to false when you open the dialog, and set it back to true when the dialog closes.
I have a tricky problem here that I have not been able to solve and neither have the people I asked on msdn forums.
I am using a third part product (signal lab from mitov.com) which is a set of .net components.
I have created a windows form app that works fine if it is run.
I now want to show this form from another form when this other form loads (or shows, or activates...).
I already have examples of this working with another form: Here is the typical code:
I am loading a form (SecondForm) from the main program...
private void SecondForm_Load(object sender, EventArgs e)
{
Form _macros = new Macros(this); //this works perfectly fine
_macros.show(this);
//this is where I have no success
Form _spectrum = new SpectrumScope;
_spectrum.Show();
}
I get various errors from no form displayed and then an exception about not instantiating the _spectrum, to an error about cross threaded operation not being allowed, to a blue screen with a message about clocks not being synchronized between processors.
If I place a button on "Second Form" and add the show form code to the click event, it works fine.
If I try to use form.activated, or form shown instead of form.load there is not difference.
If I add a time to form Shown, which then does a button.performClick, there is no difference.
Obviously the form which contains many components (and many threads behind the scene) does not like the fact that it is not being opened by the user.
I'm fairly new to C# and I'm pretty sure this is threading related.
Thank you for any help.
Try the blow code in your form load method, that should let .Net manage the threading for you.
this.Invoke(new MethodInvoker(() => (new SpectrumScope).Show()));
Well, the problem is fixed. However, I don't really know why the issue exists.
In the spectrum form I reference static variables in the secondform. Now, I use them as follows:
string newFrequency = secondForm.frequency;
This works. However, some of these variables need to have this done:
string newBandWidth = secondForm.bandwidth.substring(2,4);
This is the command that fails. I am told I need the "new" keywork.
I changed my code provide the the string without the need to get the substring and now it all works ok.
Anybody have any ideas?
When Form2 is closed, via it's X button, the Main form is sometimes hidden as well, but not always. Often times the Main form is hidden after initial 'newForm' button click and other times many open-close operations are required before the Main form gets hidden on Form2's closing. Why is this happening? Why is it irregular?
This is a small test code for a larger application I'm working on. In that application a thread continuously reads the network stream and when a particular message is encountered a modal form is displayed. The user can close that modal form or it can be told to close itself by a different network message. In this event, to give the user some time to view the data that the form is displaying I implemented a delayed form closing for that form. When the form is running its delay closing code, another message can come in over the network that will open up a new instance of this form in which case, I observed, that once the timer of the original form runs out, the original form is left displayed until the new instance is closed. Calling Hide in the FormClosing event handler closes the original form if more than one instances of it are running, but it has this side effect of hiding the entire application (the Main form) when the last instance of this form is closed, either by the user or by the delayed closing code. And again, the entire application is not always hidden, but it does happen.
//Main form's 'newForm' button
private void btn_newForm_Click(object sender, EventArgs e)
{
Form2 f = new Form2();
f.ShowDialog();
}
public partial class Form2 : Form
{
private void Form2_FormClosing(object sender, FormClosingEventArgs e)
{
Hide();
}
}
Update (from the application I'm working on):
The problem is shown visually below. The top part of the picture, labeled "A", represents the situation where the first modal dialog (greyed out) was instantiated and it is in the process of being auto closed after 4 seconds have elapsed. The second instance (blue window heading) is active and awaiting input. In the lower part of the picture, labeled "B", the counter to closing of the first instance has completed, yet the first instance remains visible. Adding Hide does not change picture "A" but picture "B" would only be showing the active modal dialog, which is what I want. If Hide is not used and we have the case shown in "B", once the active modal dialog is closed the inactive dialog will disappear together with the active one, but no sooner. At this time my main form will be hidden as well, sometimes.
Your main form doesn't get hidden, it disappears behind another window. The flaw in your code is that for a brief moment none of your windows can get the focus. Your main window can't get the focus, it got disabled by your dialog and won't get re-enabled until the dialog is fully closed. Your dialog can't get the focus, you hide it. So Windows goes looking for another window to give the focus to and can only pick a window owned by another application. Like Visual Studio, nice and big so your main window is well covered by it.
Not sure what you are trying to do, it doesn't make sense to call Hide() since the dialog will close a couple of microseconds later. Just delete the statement.
I am not sure if I am right but maybe you forgot to add e.Cancel = true; to your closing event.
Second, I think using a modal form is only usefull when you expect an action like OK or CANCEL from user, that is where DialogResults comes handy. It sounds strange if this happens time to time not all the time! maybe you can try like this:
//Main form's 'newForm' button
//Define form in your mainform
private Form2 f;
private void btn_newForm_Click(object sender, EventArgs e)
{
if(f != null) { f.Show(); return; }
f = new Form2()
f.FormClosing += delegate { f.Hide(); };
f.Show();
}
I know the topic is quite old, but I recently had to look for answers for this precise question.
Why hiding the (child modal) form instead of closing it ?
I may be wrong, but I think that in some cases, hidding the modal child form instead of closing it is sometimes useful.
For example, I'm using a class that is a custom tree of grids. Think of something like an Excel Document with multiples tables (sheets) and each table can have child tables. A very powerful manner to store datas that can be used by multiple objects and multiple forms at a time.
Now, this "TreeTable_Class" object has an inbuilt custom form that actually shows the content of one of its tables at a time in a GridView, and you can select which table to show by selecting it in a Treeview. You can see here that the "Database Editor" is actually and MDI Form that can load the Form from any TreeTable_Class.
And this is the Form I use to edit the content of a Cell for a given (selected) Table (I've chosen another cell with long text content from another table in this database)
Now, when you choose to close the custom form instead of hiding it, that form will be unaccessible, you can't show it anymore, and you get an exception (no instance of the object) Somewhat, it isn't disposed yet (so the check If MyForm Is Nothing Then... is useless) I know I have to implement the GarbageCollector and dispose the Child Form manually, but it's outside the scope of this topic.
Anyway, my class could use a large amount of memory, of datas, and if I had to rebuilt ALL the contents each time I want to show a new instance of that form, that would be a large amount of workload in my application. That's why I have chosen to hide the form instead of closing it until the main application exits or when a specific CloseFormAndDispose() method is explicitly called, either by the program, or if I make this option available for the user via an user interface.
Workaround try :
This is the workaround I've found to override the "form replaced by another because none of the parent/child ones could be retrieved" :
Sorry, I'm in VB.. but you can use a tool to convert this to C#, or do it manually, it's pretty simple..
// This is the child, a Cell Editor that can edit the content of a Cell.
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
This Editor form is a member of TreeTable_Form, a form that can actually show and edit the content of the whole Database File (a single file)
And this TreeTable_Form class contains a routine that handles CellEditor closing event
Public Partial Class TreeTable_Form
// Sorry. The "WithEvents" in C# is a litte bit complex to me... So, in VB :
Protected WithEvents _CellEditor As CellEditor_Form = Nothing
// ...
// CellEditor handling method (I used a Code converter...) :
// The original VB declaration is :
// Protected Sub RecallFormAfterCellEditorHidden() Handles _CellEditor.Closed
// You'll have to write specific Event handler for _CellEditor object declared above...
protected void RecallFocusAfterCellEditorHidden()
{
Application.DoEvents();
this.Focus();
}
End Class
This tiny protected void RecallFormAfterCellEditorHidden() method in your Class (if you are using a class that contains Forms) or in your Main From, assuming that your main form contains the child forms (dialogs) will try to force the focus on your Application or MainForm...
By the way, TreeTable_Form is actually a component of TreeTable_Class. The later is an object that can be used anywhere you want. In a Main Form Application, in another Class, in a dialog, anywhere... and could be passed by reference to share its contents between several items. And this TreeTable_Class contains a RecallFocusAfterTreeViewerHidden() method that handles the closing of that form. That means, the Form or Application that actually uses the class will get the focus each time you close the its child Form. I've made it that way to get an object that could be used anywhere
We still get problems !
However, this method will make your application flicker a bit each time you close your child dialog, and doesn't succeed at 100% ! Sometimes, my parent form still disappear from screen and gets struck behind another window. Alt+TAB wont helt either. But this happens less than without this method trick. I don't have any better answer at this time, still searching... I'll come back here if I find out how. I'm using this custom made application in my work to write memos during meetings for example, and produce PV (procès verbal - french sorry) in PDF or DOCx on the fly...
And I'm sorry, I'm in VB, not C#. Hope this helps a little, until we find a better workaround for this...
I am using Windows Form application. I want to open a small textbox on a window to enter user's name or Email in Starting for the program.
How can I achieve this?
Write one, 'tis almost trivial (creating the form and adding label, textbox and buttons) and using the VB one is perputating something that was only put in to appease the baying mob.
Key method is ShowDialog() which is a method on a Form.
On the form make sure you set the flags for the Ok and Cancel buttons correctly and provide a property (ideally) to allow you to read (and write if necessary) the text box
You can then do something along the lines of the following:
using(MyInputForm mif = new MyInputForm)
{
if (mif.ShowDialog() == DialogResult.OK)
{
dataFromDialog = mif.InputData;
}
else
{
// logic to deal with cancel
}
}
You can do something similar in WPF, don't have an example to hand though.
Maybe the answer to this question will help:
What is the C# version of VB.net’s InputDialog?