I'm developing a WPF application that's meant to live in the tool tray, so it doesn't involve any windows. Right-clicking the tool tray icon brings up a menu with a Configure Report Path... option, and I'd like to display a folder browser dialog to the user when this is clicked:
What I'm finding is that when the option is selected, a dialog opens and immediately closes unless I assign some window to Application.Current.MainWindow and show it before opening the dialog. This is the code I'm using:
public CounterIconViewModel(IMessenger messenger)
{
void ConfigureReportPath()
{
// Application window must be created and displayed.
Application.Current.MainWindow = new Window();
Application.Current.MainWindow.Show();
var browseDialog = new VistaFolderBrowserDialog { ShowNewFolderButton = false };
if (browseDialog.ShowDialog() != true)
{
return;
}
// (Separate issue) Command doesn't execute unless I comment out the line below.
//messenger.Send(browseDialog.SelectedPath, "ReportPath");
}
ConfigureReportPathCommand = new RelayCommand(ConfigureReportPath);
ExitApplicationCommand = new RelayCommand(Application.Current.Shutdown);
}
In this case I'm using VistaFolderBrowserDialog from Ookii.Dialogs.Wpf, but I've tried the same thing with another WPF browser dialog and notice identical behaviour.
Is there a reason why a browser dialog seems to require a window to be displayed to remain open, and any workarounds?
Update
I've found that if I initialize and pass an instance of Window to browseDialog.ShowDialog, the dialog remains open without me having to assign the main application window and display it:
if (browseDialog.ShowDialog(new Window()) != true)
I don't understand why this works. I'll post this as an answer if no others appear so that at least people in a similar situation are aware of this workaround.
Update 2
The other dialog I tested it with was CommonOpenFileDialog from Microsoft.WindowsApiCodePack-Shell:
var browseDialog = new CommonOpenFileDialog { IsFolderPicker = true };
browseDialog.ShowDialog();
My tool tray icon displays a rich tool-tip (a custom UserControl) if I hover over it, and with this browser dialog I found that:
If I hover over the icon to make the tool-tip display, then the browser dialog works fine when I try to open it on the first and every subsequent attempt.
If I try to open the browser dialog before displaying the tool-tip display, the browser dialog opens and closes immediately on the first try, but then remains open on every subsequent attempt.
This dialog also accepts a Window instance in ShowDialog but it makes no difference if I pass one or not.
My workaround (initializing and passing a blank window to the Ookli dialog browser) seems to work fine regardless of whether I first bring up the tool-tip, so I'm sticking with that for the time being.
I am developing an Outlook plugin using add-in-express. I have added an adxOlFormsManager there. Which contains a Forms collection named ‘adxOlFormsCollectionItem1’. I have set the form class name to as “FlowOutlook.Plugins.Chat.ChatExplorerPane”. Yes, ChatExplorerPane is my ADXOlForm.
I implement a custom event for the my ADXOlform using following code:
private void AddinModule_AddinStartupComplete(object sender, EventArgs e)
{
try
{
var currentChatTypeForm = AddinModule.CurrentInstance.adxOlFormsCollectionItem1.FormInstances(0) as ChatExplorerPane;
currentChatTypeForm.OnChatTypeSelected += currentChatTypeForm_OnChatTypeSelected;
}
catch (Exception ex)
{
Debug.DebugMessage(2, "AddinModule : Error in AddinModule_AddinStartupComplete() : " + ex.Message);
}
}
My Problem is :
If I explorer layout as “RightSubpane” this works fine. But after I changing the explorer layout as dock right (using Properties window), adxOlFormsCollectionItem1.FormInstanceCount is 0. (Which means “currentChatTypeForm” will be null).
What I am supposed to do :
private void ChangeExplorerLayout(AddinExpress.OL.ADXOlForm form)
{
if (form == null) return;
form.XXX = AddinExpress.OL.ADXOlExplorerLayout.DockRight;
}
I wrote above method to change the explorer layout by code. I hope I may be able to call that safely inside AddinModule_AddinStartupComplete, after initializing my custom method. But I need to know the code for replacing ‘XXX’ to complete the method and have a try.
Please advice me to change explorer layout as dock right according to my requirements.
Kushan Randima.
Below is a citation from the manual - see section Accessing a Form Instance in the PDF file in the folder {Add-in Express}\Docs on your development PC.
It is essential that Add-in Express panes are built on the windowing of the host application, not on the events of the application's object model. This means that getting an instance of an Add-in Express pane in a certain event may result in getting null (Nothing in VB.NET) if the call is issued before the pane is shown or after it is hidden. For instance, it is often the case with WindowActivate/WindowDeactivate in Excel, Word, and PowerPoint.
...
So, you may encounter a problem if your add-in retrieves a pane instance in an event above. To bypass this problem, we suggest modifying the code of the add-in so that it gets notified about a pane instance being shown or hidden (instead of getting the pane instance by handling the events above). Use the ADXBeforeTaskPaneShow event of the task pane class (Excel, Word, and PowerPoint) and the ADXOlForm.ADXBeforeFormShow (Outlook) event to be notified about the specified pane instance being shown. When the form becomes hidden, you'll get ADXOlForm.ADXAfterFormHide (Outlook) and the ADXAfterTaskPaneHide event of the task pane class (Excel, Word, and PowerPoint).
That is, instead of getting a form instance in the AddinStartupcomplete event, you can handle the ADXOlForm.ADXBeforeFormShow event.
Hope this helps.
How do you change page/screen display in c# windows forms without using Close(); and Show(); ?
Close(); and Show(); makes the screen blink and I want it to be fluent. Can I use the menustrip to change screen ?
You can create the new window at exactly the same size and position as the original, and then do a ShowModal on it. When the new window closes, though, you will be back to the original window.
You can make it the same form, but display the controls of each window in different tab pages of a TabControl. I'm not sure offhand how to hide the Tabs which allow the user to change TabPage but I think it can be done; or it might be a good thing to have them there, depending on your requirements.
You can do the Show as you are doing currently, but don't do the Close() of the original form. Instead, when the original form creates the new one, it should subscribe to an event (Activated? or create a special one fired by the new window when it's finished displaying itself) and when it receives that event it calls Close() on itself.
There's three possible ways.
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 have a form which instances a new form that I've already created using
statuswindow statwin = new statuswindow();
statwin.ShowDialog();
return statwin;
This code is in a function. The problem is when I run the function in other code the next line of code doesn't run until the newly instanced window is closed by the user, I'm guessing this is the side-effect of using ShowDialog(), is there a way to have it use the same behaver (being topmost, not being to select the other main window) while still letting the main form's code run?
Update: Although Show(); will work, I need to be able to make the window like a dialog by having it always on top of the other window and it always being the active selected window.
The ShowDialog method of showing a window shows it as a dialog, which is a blocking mechanism within C#/.net. If you want to simply display the window and not cause the running code to block until it is closed, you can use the window.Show() function.
In your code:
startwin.Show();
This will cause the startwin form to become visable to the user, and will fire the startwin.VisibleChanged event as well as the startwin.Load event to fire.
To make the new window always on top, you could set the Topmost window flag in the form properties.
To make the window run in a separate thread, first spawn the thread, then create the window from that thread.
There are also "application modal" and "system modal" Win32 window flags, but I don't know if those are exposed to WinForms or not -- go have a look on the form properties!