Invoke throwing InvalidOperationException - c#

I'm having a bit of an issue that I'm stumped on and I was hoping someone could shed some light on it. I have a Form called form2 and I'm running some code to add some items to the Listview(s) of that form using a MethodInvoker so that the UI thread stays responsive while I do so.
Everything runs fine with it the first time around but then when I close that form (the one with the Listview on it) and run my code again I get a InvalidOperationException: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
So I looked into this and Googled it a bit more as well as looked on StackOverflow and I saw the issue was being caused by the form not having a handle created for it since it's being disposed when it's closed the first time.
So my solution was to have it force the form to set a handle for itself via CreateControl(). Even after using this, my form still isn't setting the handle when I inspect it in the break from the exception. It has 00x0000000 or something like that, and I'm still getting my InvalidOperationException. I have also tried to checked .isDisposed() and tried to use CreateControl() after that with no luck. Have any of you guys heard of this before? The other threads on SO have yield no solutions for me.
My Code:
if (!form2.IsHandleCreated)
{
form2.CreateControl();
}
form2.Invoke((MethodInvoker) delegate
{
//Do Stuff Here.
}

So since nobody responded to this I'll answer my own question in case anybody comes across this and it helps them. I actually ended up putting this outside the scope of my new thread that was created and creating the form in a button click event. I then checked to see if my form was Disposed or still open and created new instances of the Form based on that.
This is my code:
var checkDMS = CheckIfNull(dealtxt.Text);
if (checkDMS)
{
//If DMS Deal is valid -> If Form is Closed ->
if (form2.IsDisposed)
{
// If Form not open -> Create new instance
form2 = new Form2();
form2.Show();
form2.SendToBack();
}
else
{
// If Form still open -> Close and make new instance.
form2.Close();
form2 = new Form2();
form2.Show();
form2.SendToBack();
}
runDMSQueryFromNewThread(materialCheckBox1.Checked);
}
else
{
MessageBox.Show("Cannot Pull Deal From DMS.");
}

Related

c# - How to set all the application as the owner of Form.showDialog()

I have a Windows Desktop App with an auto-update method implemented. I want to show a custom Form (because I need to change the button texts) asking the user if he or she wants to download the new version or not when a new update is detected and I want to "block" all input actions in the Desktop App until the user has made his selection.
After reading Form.ShowDialog() documentation and several topics here saying "ShowDialog() is not making my windows modal" and several answers replying "You need to properly set the owner" I still don't understand how to set this owner. Of course if I make two forms and the first one shows the second, I can "block" the first one doing:
secondForm.ShowDialog(firstForm);
But I don't know how to make that the firstForm blocks all the application to prevent the user using a deprecated version of it.
I tried several approaches like getting the current id process (or trying to get it) and convert it to IWin32Window. But nothing seemed to work.
If you need it, I add here the code I'm using:
FormAsk formAsk = new FormAsk (param1, param2);
formAsk.StartPosition = FormStartPosition.CenterParent;
formAsk.TopLevel = true;
formAsk.TopMost = true;
formAsk.DialogResult = formAsk .ShowDialog();
if(formAsk.DialogResult.Equals(DialogResult.OK))
{
// do stuff
}
else
{
// do other stuff
}
I've also seen lots of solution implementing:
myForm.ShowDialog(this);
But VS start's crying because the types are not compatible. I'm using a MVVM pattern so I can't just set a Form as an owner because I don't have a main form. Just views in .xaml and views controllers in c#.
Edit: I would like to add few comments I learned after facing this issue that may help to understand better my situation.
The main method of the program executes the following:
[STAThread]
static void Main()
{
//stuff
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
{
//stuff
STAApplicationContext context = new STAApplicationContext();
Application.Run(context);
}
catch (Exception exc)
{
MessageBox.Show(exc.Message, Localization.Strings.error_popup_title);
Application.Exit();
}
}
}
And this context is the one that generates the service layer and views manager of the application. If I display the Forms in the service layer, showDialog() method can not "block" the input in the views but if I display them from the views (generated and handled by the view manager) i can. There's a communication between views and service, because actions triggered in the views have as consequence a service method call, but in this case the communication I want is the opposite: the service calling the methods in the view controllers to display the Forms by showDialog().
You need to pass an instance of the IWin32Window interface to the ShowDialog method.
IntPtr myWindowHandle = IntPtr(parent.Handle);
IWin32Window w = Control.FromHandle(myWindowHandle);
Do your Stuff in your first Form and whatever button you press to create your second Form just go like this. (Pseudo Code)
button1_click()
{
Form2 = new Form()
Form2.Owner = this;
}
and now from your Form2 you can talk to your Owner with this.Owner.Visible = false for example.
Thats how you make the Owner if thats what you asked for.
Thanks those who tried to help with your replies. However, although your answers probably will work in other circumstances, mine where a bit different.
Finally I achieved to solve it, I needed to do the handle with Forms in a higher level of abstraction. The information managed was retrieved from an asynchronous task so I couldn't use there a showDialog method and block the MainWindow of the application. Instead I did several threads, wait them and eventually show dialogs when I needed. It's not the best approach, but given the context is the only thing I could do.

ShowDialog and Dispose problem with Forms..NET 3.5

Im fixing some errors in an existing C# project.
I use Visual Studio 2008 and 3.5 .NET Framework.
The application uses Forms, and the lifecycle of the application worked correctly. I didn't did any changes yet, but the client started experiencing strange behaviour lately.
The can use the app the first time without problems, but if a form is closed and we open another one, the objects in this form are Disposed.
The code is for a PDA, and we have a EventHandler for the Scan.
I belive this is very strange as nothing from the code has been changed.
Maybe it is some framework bug?
I've tried to completely eliminate the event handlers on the Closing event, but the same error happens.
Changing the way the forms are disposed.
Form creation
FormTEntreUbicaciones form = new FormTEntreUbicaciones(Movements.TREntreUbicaciones);
form.ShowDialog();
form.Dispose();
Event creation
if (Device.GetOSType2() == Device.OSType.WinMobile){
hDcd = new DecodeHandle(DecodeDeviceCap.Exists | DecodeDeviceCap.Barcode);
DecodeRequest reqType = (DecodeRequest)1 | DecodeRequest.PostRecurring;
dcdEvent = new DecodeEvent(hDcd, reqType, this);
dcdEvent.Scanned += new DecodeScanned(dcdEvent_Scanned);
}
The form should be open, and all the objects in it should NOT be disposed
Exception:
System.ObjectDisposedException was unhandled
Message="ObjectDisposedException"
ObjectName=""
StackTrace:
at System.Windows.Forms.Control.InvokeHelper(Delegate method, Boolean fSynchronous, Object[] rgobjArgs)
at System.Windows.Forms.Control.Invoke(Delegate method)
at Datalogic.API.DecodeEvent.WaitForScan()
Any suggestions?
Thanks!
Finally, I found a solution.
After figuring out what was going wrong, I found out that the SCAN event was kept alive.
I added a Closing override:
this.Closing += MyClosedHandler;
And the MyClosedHandlerEvent as follows:
//FIX MA 23.07.2019
protected void MyClosedHandler(object sender, EventArgs e)
{
if (dcdEvent.IsListening)
{
dcdEvent.StopScanListener();
}
if (hDcd != null)
{
hDcd.Dispose();
}
}
Problem was detected with datalogic.api.dll. The PDA used is the Skorpio x3.
Hope this will help somebody else!

Fully closing application in C# just won't work [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm writing a simple game and I have a function that basically should just exit the application or rather close everything currently open in C# (I'm using Windows Forms).
private void ExitApp()
{
Application.Exit();
}
However, nothing will work. I have tried using Environment.Exit(0), Application.Exit, tried using a for loop to close every form but it just won't work. What I have noticed is that even if I press the X button, the solution won't close, but something seems to be running in the background and I do not know what. Browsed Stackoverflow forum for similar issues, browsed other forums, googled for days, but nothing seemed to help.
This is the code for opening more forms :
Podešavanja p = new Podešavanja();
private void Settings_FormClosing(object sender, FormClosingEventArgs e)
{
this.Close();
Menu m = new Menu();
m.Show();
}
private void button1_Click(object sender, EventArgs e)
{
this.Close();
Menu m = new Menu();
m.Show();
}
The SettingsFormClosing event actually just opens up a new Form for me, without closing the previous one, why, I do not know.
Any help would be greatly appreciated.
The problem is that your forms are all running on the same thread. Take a look at your Program.cs file. See how it calls Application.Run(New Form1())? This is where your application form initially runs on the application thread.
So the problem we have here is: you are trying to close your Form, which is hosting your second form. Suppose your a single form with a button control on it. Now suppose you tried to tell your application you wanted the window form to close, but wanted the button to stay active and open -- crazy right? Well what you are trying to do is essentially the same thing -- mind you I am basing this on the assumption you are not multithreading. Your Form1 is hosting your Form2 instance, and thus you cannot run Form2 if Form1 is disposed. The best way I can think of, at least off the top of my head, is you need to create a recursive call in your Program.cs and tell it whether or not it needs to run a new Form before it truly exits. This is questionable at best, but it might suffice.
So let's modify our Program.cs Then:
static class Program
{
//This is where we set the current form running -- or to be run.
static Form CurrentForm;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Obviously, Form 1 starts everything so we hardcode that here on startup.
CurrentForm = new Form1();
//Then call our Run method we created, which starts the cycle.
Run();
}
//This runs the current form
static void Run()
{
//Tell our program to run this current form on the application thread
Application.Run(CurrentForm);
//Once the form OFFICIALLY closes it will execute the code below
//Until that point, imagine Application.Run being stuck there
if(CurrentForm != null && CurrentForm.IsDisposed == false)
{
//If our current form is NOT null and it is NOT disposed,
//Then that means the application has a new form to display
//So we will recall this method.
Run();
}
}
//This method is what we will call inside our forms when we want to
//close the window and open a new one.
public static void StartNew(Form form)
{
//Close the current form running
CurrentForm.Close();
//Set the new form to be run
CurrentForm = form;
//Once all this is called, imagine the program now
//Releasing Application.Run and executing the code after
}
}
Okay so if you wrap your head around this, then closing and opening a new form is a piece of cake. We simply can open new forms on button click events.
Inside Form1.cs:
private void OpenForm2_Click(object sender, EventArgs e)
{
Program.StartNew(new Form2());
}
Inside Form2.cs
private void OpenForm1_Click(object sender, EventArgs e)
{
Program.StartNew(new Form1());
}
I will reiterate, this method is super questionable.... But it may suffice for what ever you are doing. It is also super reusable through your application regardless of the class or form.

Methods this.hide() vs this.close()

My c# windows forms application has 5 forms which I am displaying one after the another. When the user clicks on next button, the code I have given is:
new Form1().Show();
this.Hide();
However I do not want my current Form to hide. I want to close it/dispose it so that it does not consume memory. I want to release its resources like the images and variable used as soon as I am done with it.
For that I tried implementing:
new Form1().Show();
this.Close(); //Form 2
but this simply closes both the forms.
I even tried swapping the positions of the above two lines:
this.Close();
new Form1().Show();
but this also does same thing.
How do I release the resources of one form as soon as I am done with it? because my program throws out of memory exception when I try to re-open my Form 2 using:
new Form2().Show();
this.Hide();
You can start your NewForm in a new thread and create a new message loop
When the main message loop is closed, the application exits. In Windows Forms, this loop is closed when the Exit method is called
For more information see here.
var th = new Thread(() => Application.Run(new NewForm()));
th.SetApartmentState(ApartmentState.STA); // Deprecation Fix
th.Start();
this.Close();
Another way to do it, is to manage the application context yourself. Here is a small demo:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
using (var myApplicationContext = new MyApplicationContext(new Form1()))
{
Application.Run(myApplicationContext);
}
}
You can define your tailored made ApplicationContext in the following way:
public class MyApplicationContext : ApplicationContext
{
public MyApplicationContext(Form mainForm)
:base(mainForm)
{
}
protected override void OnMainFormClosed(object sender, EventArgs e)
{
if (Form.ActiveForm != null)
{
this.MainForm = Form.ActiveForm;
}
else
{
base.OnMainFormClosed(sender, e);
}
}
}
And now, you could do the following on the Button.Click event handler:
var f = new Form();
f.Show();
this.Close();
And the application will keep on running. Basically this way you keep the app alive while there is at least one active form.
NOTE Haven't tested it but it should work.
Closing the form which the Program start in its main function will close the application, an idea is to have a parent Form and make it the main form, and never close it, this can be a hidden form if you want.
I am not working with Windows forms since long time ago but found on this page the reason behind behavior you are getting:
http://msdn.microsoft.com/en-us/library/ms157902(v=vs.110).aspx
Typically, the main function of an application calls this method and
passes to it the main window of the application. This method adds an
event handler to the mainForm parameter for the Closed event. The
event handler calls ExitThread to clean up the application.
Also on this question How do I prevent the app from terminating when I close the startup form? there was a discussion about something the same
I am not sure if it would work for you. But when I had the same problem while dealing with a login form... i just used ShowDialog() instead of Show() , (and for me it solved the problem ) Just Like:
this.Hide();
MainForm MForm = new MainForm();
MForm.ShowDialog();
this.Close();
By default, a C# Forms application creates a "root" form in the Program.Main() method and passes that to the Application.Run() method. When this Form is closed, your program will exit.
However, you can change this behavior by using a different Application.Run() overload. Just don't pass the Form instance to Run(). Instead, show the form before calling Application.Run(), and then later on (when you finally do want the program to quit) use the Application.ExitThread() method to tell the Application class you're ready to close the application.

Instantiate a form, then find it later, without showing it initially

I am having a problem that is strange to me but hopefully is not so strange to someone else. : ) Some background: I am working on a simple IM client that allows the user to broadcast messages to multiple recipients. The goal is to create a chat form for each of the recipients containing the text of the broadcast message, then show that form only if the recipient responds to the broadcast-er. However, when the application receives a response then attempts to locate the form for that particular chat session (using Application.OpenForms) it cannot find it UNLESS I .Show at the time it is created. I would like to avoid having to show this form when it is created because this means that the user will see a flash on the screen. The form doesn't seem to really be created until I show it, but it would seem there has to be a way to do this without showing first. Can anyone assist?
I can provide code snippets if needed, I didn't in this post because this feels more like a conceptual misunderstanding on my part than a bug in the code. Thanks in advance!
Instead of using the form as a base class, do it the other way, create a class that can reference a form. That way, you'll keep the class informed of the content, and reflect it on the form (if it's initialized), not the other way around.
You shouldn't rely on Forms as a basis of your objects. Using Application.OpenForms should be unnecessary.
public class Contact
{
string displayname = String.Empty;
List<Message> history = new List<Message>();
MessageForm theform = new MessageForm(this);
public void OnEvent(Message msg)
{
if(msg.Sender != me && !theform.Visible)
theform.Show();
}
public void Tell(string message)
{
}
}
etc
Keep your contacts in some sort of list, and things should be relatively simple.
(Be aware that windows forms aren't thread-safe, and will throw an exception if you try to alter any properties of any of the controls from a different thread than main)
windows form has methods like Hide(),Show() and Activate(). use these method for your problem.
Why not store a reference to the form with the chat session and use that to call .Show() when you need to display the form:
session.form.Show();
You can then create the form without showing it and you don't have the overhead of calling Application.OpenForms each time you want to reference it.
I know this is stating the obvious but OpenForms won't find a form that hasn't been shown because it's not open.
As the form handle does not get created until the form is shown you can assign it manually like so:
mf = new MainForm();
/* Need to assign a handle to MainForm instance manually
as handle does not get created until form is shown */
IntPtr handle = mf.Handle;

Categories

Resources