Revit API External Command freezing after WinForms Close() event - c#

I am trying to create an external command for Revit that pops up a windows forms that has a single text box for the user to enter a description. After the user clicks Ok, the form closes but Revit gets stuck in a loading motion. It doesn't freeze, it just is constantly loading something. When I pause debugging, the code only made it to the line form.ShowDialog(). If I take out the showdialog and just run it without the form, it runs fine.
I'll post my relevant code snippets below. The form is in its own .cs, separate from the external command .cs but still under the same namespace.
Form click events code:
private void CancelForm(object sender, EventArgs e)
{
isReport = false;
this.DialogResult = DialogResult.Cancel;
Close();
}
private void SubmitForm(object sender, EventArgs e)
{
isReport = true;
reportDesc = descriptionBox.Text;
this.DialogResult = DialogResult.OK;
Close();
}
Execute command:
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
//Get application and document objects
UIApplication uiapp = commandData.Application;
Document doc = uiapp.ActiveUIDocument.Document;
ReportForm ticket = new ReportForm();
ticket.ShowDialog();
The code stops processing after showdialog. From what I could read on it, I thought it might have to do with focus on Revit after the form closing or the form not closing properly but couldn't figure out how to fix it.
Any help would be greatly appreciated!

Here is an old sample that creates a minimal Windows form on the fly, displays it as a modal form and closes successfully afterwards: The Schedule API and Access to Schedule Data. Maybe that will help. Maybe the debugger is interfering with the form closing somehow?

I ended up remaking the entire addin, made sure I was using Jeremy Tammik's Revit Addin Wizard to initiate it, and it started working. Not exactly sure what fixed it but guessing it was some error in the set up or such.

Related

Windows forms Form closed event not working with opening a new form

I have some code meant to open a new windows form when one is closed, and yet I get nothing, no error.
I've tried a few different methods for opening a new form on a Form.FormClosed event.
This is the code I have right now:
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
Form1 myForm = new Form1();
myForm.Show();
}
But yet I get no error, nothing.
I'm expecting for a new windows form to be opened when I close another one.
Any help would be appreciated, thanks!
The problem is that as soon as the first Form1 instance closes, your application shuts down and exits because the application message loop is defined with the initial Form instance, and it is just waiting for events on that form until it closes. On closing, the application will exit, opening a new form doesn't stop this process.
You need to adjust the Main() method in Program.cs to look something like this:
[STAThread]
static void Main()
{
// ... Application configuration as required here
new Form1().Show(); // The first form instance is now no longer bound to the Application message loop. Start it before we begin the run loop
Application.Run(); // Don't pass in Form1
}
Your original code should now work. I might add however, this is not a great user experience. Carefully consider what you're trying to achieve, and perhaps consider alternatives - do you just need a "reset form" button? Or is the primary goal to prevent a user from closing the application? If the latter, you can remove the Close icon altogether.
Perhaps something simple to get your going forward.
private Form1 myForm = new Form1(); //Declare the form as a private member variable
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
e.Cancel = true; //Cancel the closing so this object stays alive
this.Visible = false; //Hide this form
myForm.Show(); //Show the next form
}
Please note #pcdevs comment. You'll need a way to indicate the form is being closed/application quiting vs progressing to the next step/form. You might want to look at some CodeProject articles about "C# Winform Wizards", those sequential dialog prompt apps...

ShowDialog is just looping and creating new forms

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.

How to bring the main form back to the front after the file open dialog is closed

My C# application starts by opening a form. In the constructor for that form I "showDialog" an openfiledialog. After selecting a file to open, the openfile dialog closes, the file is loaded and the contents displayed in the main form but the main form is buried behind every other open window on my desktop.
I have to find it in the task bar and bring it to focus. I just started the application, I want the form to have focus.
I have written other applications that do not use the openfiledialog and when I start them the main form opens with focus as you would expect.
How do I make the main form get focus after the openfiledialog closes?
I have tried
this.focus(),
this.activate(),
this.bringtofront();
and this.TopMost = true;
None of them make any apparent difference at all.
I have research this problem extensively and this are the things everyone suggests and say work, but they don't work for me. Some have insinuated that I am violating all that is holy by trying to make my form topmost. However, I don't think very many people would like to open an application and have the main form for it show up behind everything else.
Any one have any other ideas about how to make sure my form is "in front", topmost, has focus?
When you do it this way, your application will have a brief moment where no window is available to receive the focus after the dialog closes. Windows is forced to find another window to give the focus to, that will be a window of another app. Your main window eventually appears, now behind that other's app window.
Display the dialog in an event handler of the Shown event instead. Or use the boilerplate File + Open command.
SOLUTION: this.Activate(); works but if called from the form Load event.
This will set the window on top:
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
private void Form1_Load(object sender, EventArgs e)
{
....
//after your code place the call to the function at the end.
SetForegroundWindow(this.Handle);
}
Althought as Mr. hans said and very well you are better off with another design.
If you can, move the ShowDialog out of the constructor, or try putting this in the constructor:
this.Shown += OnShown;
and move your ShowDialog to here:
private void OnShown(object sender, EventArgs eventArgs)
{
var result = new OpenFileDialog().ShowDialog();
}

FolderBrowserDialog not showing up on second form

Ok, this is the main essence of what I am trying to achieve and the symptoms of what it is doing.
I have a main windows form. On this form the user can click on a button that will open up a new and seperate form. This form will have a button that is supposed to display a FolderBrowserDialog. Instead it simply locks up form2 and never displays anything.
Here is essentially the code I have dealing with the form etc.
This is in the first form that is loaded after i do some uninteresting things.
FORM1.cs
//do stuff
//In a button.click method I do the following
Application.Run(new Form2(myParameters1, 2, 3));
This is the second form that is called from the first form
FORM2.cs
//do more stuff with the parameters on load
//user clicks on a button
private void button1_Click(object sender, EventArgs e)
{
FolderBrowserDialog fbd = new FolderBrowserDialog();
fbd.RootFolder = Environment.SpecialFolder.Desktop;
fbd.Description = "This is the browser dialog box";
if(fbd.ShowDialog() == DialogResult.OK)
{
//do stuff
}
}
After I click on the button the dialog box does not show up and the form2 gets locked from doing anything.
I have also attempted changing the
fbd.ShowDialog()
To
fbd.ShowDialog(Form2.ActiveForm)
with the same results.
Any help would be appreciated! If you need more info let me know and I can try to provide all that I can.
EDIT
I forgot to mention (and actually completely forgot) That the method that opens up the second form is a seperate thread.
So the first form starts a thread, which opens the second form, which is supposed to open a dialog which it is not. Now i think it has to do with the threading..
I have figured out my issue. It ended up being that the thread from Form1 that was opening Form2 was not able to open DialogBoxes because it was seperate from the UI thread entirely.
I ended up working around using that thread and just eliminated it completely which solved my problem. The dialog box opened up just as I wanted.
Thank you all for the responses though! They did help me figure out a few other things I failed to do correctly.
I had similar problem. Main GUI thread was creating a backgroundworker thread to write to database but when background thread is failed used to show a custom control dialog to save exception file. THis custom dialog was shown correctly however Browse button on it to open folderBrowserDialog to save the exception file wouldn't show. My custom control would show "Not Responding" in its title bar.
What I did was instead of calling Custom Control directly I made it call on UI thread itself
like this.
void DBThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
this.Invoke(new CrossThreadExceptionHandler(CatchInterThreadException), e.Error);
}
}

Application window sent behind other windows on closing different thread (C#)

I'm writing a Windows Forms Application in C#.NET
On startup, the application displays a splash screen which is running in a separate thread. Whilst the splash screen is showing, the main application is initialising.
Once the main application has finished initialising, the main form of the application is displayed, and the splash screen still shows over the top.
Everything so far is as expected.
Then, the Splash screen is closed, which causes that thread to exit. For some reason, at the point, the main application windows gets sent behind all other open Windows, notably the Windows Explorer window where you clicked the .exe file to run the application in the first place!
What could be causing the windows to suddenly jump "behind" like this?
Try calling .Activate() on your main window when your thread closes.
It's never been active, and thus has low Z-Order, so whatever is higher will naturally be above it. I had to fix this exact scenario in our app.
Don't forget! You may need to marshal the call to the correct thread using an Invoke()!
I've had this happen at times too. Bob's response is the easiest and works for me in the majority of cases. However, there have been some times where I need to use brute force. Do this via interop like this:
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Is the splash screen a Modal dialog?
I have seen this window 'jumping' if you dismiss a Modal dialog twice by setting both DialogResult and calling Hide() or close().
Code like this:
private void button1_Click(object sender, System.EventArgs e)
{
this.DialogResult = DialogResult.Abort;
this.Hide();
}
See this blog entry for all of the cases...
You can use code like this :
private void button1_Click(object sender, System.EventArgs e)
{
this.DialogResult = DialogResult.Abort;
this.Hide();
}
Thanks all!

Categories