Controlling many forms at the same time - c#

Suppose, I have the following task.
There is a main application form with numerous buttons; when you click on each of these buttons, you get one more form. The second click on the button should close the opened form.
These forms should not be shown in taskbar, because they are auxiliary. They should not be dialog, because that will block the main application form and prevent user from performing some other operations with the main window or with other forms like the one that is opened. They should be shown above the main form, but not above other windows (so TopMost doesn't suite). When such forms are closed, the main form should be notified, and when the main form is minimized, they should be minimized as well.
How would you solve this problem?
The current solution is based on using hooks. It's not very easy to understand and very difficult to maintain (mainly because I am not experienced in win32). It works fine for about 90% of situations, but in 10% it doesn't.
Maybe, the requirements to forms behavior are to strict?

I would recomment using some window-manager, so each button will tell the window-manager to toggle visibility of form X, if X is not there it will be shown, if it is, it will be closed.
You should be able to configure the windows such that they will not show up in the taskbar.
For the visibility, I am not sure what you mean. When you open a form via a button, it will usually go to front, which should be ok. If you switch the window then, what do you expect? Should the main window always stay in the background or is it allowed to come to the front when focused?
Whenever I have seen applications change such standard behaviors, they failed in some way. Either wrong windows showed up or some were not accessible anymore or the user was just confused because these windows didn't act like all other windows.

It's not a problem. Use the Show(owner) overload to display the form.
An owned form is always on top of its owner. It minimizes automatically when you minimize the main window. No need for ShowInTaskbar. Another window model supported by winforms is MDI, check out the MdiParent property. The child windows are confined inside the bounds of the main window. Also consider using UserControls instead of a form, you can swap them in and out as needed. Or a tabbed interface, using TabControl. Weifenluo's DockPanel suite is a very popular implementation of the Visual Studio style windowing model, supporting windows that can be docked and floating within the main window. Plenty of choices here :)

Here's how most of your requirements can be accomplished:
Set the Owner of each child Form to be the Main Form.
MSDN Quote:
When a form is owned by another form,
it is closed or hidden with the owner
form. For example, consider a form
named Form2 that is owned by a form
named Form1. If Form1 is closed or
minimized, Form2 is also closed or
hidden. Owned forms are also never
displayed behind their owner form. You
can use owned forms for windows such
as find and replace windows, which
should not disappear when the owner
form is selected. To determine the
forms that are owned by a parent form,
use the OwnedForms property.
For stoping a form from appearing in task bar you need to set the ShowInTaskBar property

Related

Making window topmost inside app only

I have app which opens several windows at the same time. One window (we'll call it MainWindow) is the main window of the app. From that window, I open several other windows using Show() method and set Owner property of those child windows to MainWindow. According to this MSDN article, if the owner is set on those kind of windows, main window will ALWAYS be behind child windows
An owner window can never cover an owned window.
The question is: is there a scenario which will allow me to retain parent-child relationship (I need this since I need to be able to iterate through child windows) and to have main window in front of all other windows in the app all the time? One key note: windows must be opened with Show(), and not ShowDialog() method.
I've experimented with Topmost property, using Activate() and Focus() methods, but haven't found a way to do it.
The easiest way to create a parent/child relationship and to be able to bring a parent window to front is to create a cusom form class, give it an property for your childs which you can use to iterate them and then simply inherit all your forms from your custom form class.
Then Activate() or Focus() should work.

C# TopMost and Tray

I have a WinForms application which shows a new small Form (with TopMost set to true) when a hotkey is pressed.
However when I send my main Form to the tray, the second Form is still displayed on the desktop.
How can I set my Form always to display on top of all applications, or just on top of the currently focused application?
Reference: Form.TopMost.
Form.TopMost will work unless the other program is creating topmost windows. There is no way to create a window that is not covered by new topmost windows of another process.
"How do I create a window that is never covered by any other windows, not even other topmost windows?"
Imagine Ans. if this were possible and imagine if two programs did this. Program A creates a window that is "super-topmost" and so does Program B. Now the user drags the two windows so that they overlap. What happens? You've created yourself a logical impossibility. One of those two windows must be above the other, contradicting the imaginary "super-topmost" feature.

How do you keep a .NET form always above another application?

I have a C++ app that is running as the main application. A .NET app is also running side by side and I have interprocess communication via sockets. How do I maintain the .NET main form above the C++ app?
Methods:
Currently I've set TopMost = true but this causes problems when you open another application : the .NET app appears above all other apps.
Another way would be to check when you LostFocus, if the user has clicked on the C++ app then you bring the .NET app to the foreground, and if the user switched to another app then do nothing.
Any ideas? Has this ever been done before? I've seen a similar effect in Paint.NET, where the tool palettes remain on top of the other window.
Have you tried making the C++ window the owner of the .NET form, before showing it? Window handles are session-global, so you can communicate them via IPC. And the Show method accepts any IWin32Window as owner. From the MSDN page:
When a form is owned by another form, it is closed or hidden with the owner form. For example, consider a form named Form2 that is owned by a form named Form1. If Form1 is closed or minimized, Form2 is also closed or hidden. Owned forms are also never displayed behind their owner form.
Response to comment:
Maybe this wasn't clear enough: The Owner property is of type Form, so you can't assign it any IWin32Window object once the form is visible. But Form.Show does accept an IWin32Window owner parameter - so you can set the owner to any window when you first show your form. I've looked at Form.Show in Reflector, as far as I can see, it should handle any IWin32Window parameter, even if it's not a Form.
If you need to set the window owner later than the first call to Form.Show, then you'll probably have to PInvoke SetWindowLong (as described in this answer). That's what Form.Show does, too.

What's difference between ShowDialog() and ShowDialog(IWin32Window) in c#?

Both ShowDialog(); and ShowDialog(IWin32Window); seem to do the exact same thing to me. The documentation isn't very clear either.
I've been told that ShowDialog(IWin32Window); will ensure that the dialog window is on top of the whatever is passed in as the owner window.
The MSDN documenation makes no mention of this, so it feels like a bit of black magic.
http://msdn.microsoft.com/en-us/library/w61zzfwe.aspx makes it pretty clear that the parameter represents the owner window. And that is the behavior of an owner window - it stays behind its children and doesn't close leaving its children still displayed.
When ShowDialog() is called, the currently active window is made the owner of the dialog box. If you want to specify a specific owner, use the other version of this method (ShowDialog(IWin32Window)).
This is stated in the MSDN documenation.
http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx
Internally ShowDialog() calls ShowDialog(IWin32Window) with a null argument. If the argument is not null, it is set as the form's owner. If owner is null, it will use GetActiveWindow() to get a IntPtr to the active window and use this as the owner. You can check it out yourself using ILSpy.
.NET allows a form to “own” other forms. Owned forms are useful for
floating toolbox and command windows. One example of an owned form is
the Find and Replace window in Microsoft Word. When an owner window is
minimized, the owned forms are also minimized automatically. When an
owned form overlaps its owner, it is always displayed on top.
(c) "Pro .NET 2.0 Windows Forms and Custom Controls" by Matthew MacDonald.
As ShowDialog shows the new form, an implicit relationship is
established between the currently active form, known as the owner
form, and the new form, known as the owned form. This relationship
ensures that the owned form is the active form and is always shown on
top of the owner form.
One feature of this relationship is that the owned form affects the
behavior of its owner form (when using ShowDialog):
The owner form cannot be minimized, maximized, or even moved.
The owned form blocks mouse and keyboard input to the owner form.
The owner form is minimized when the owned form is.
Only the owned form can be closed.
If both owner and owned forms are minimized and if the user presses Alt+Tab to switch to the owned form, the owned form is activated.
Unlike the ShowDialog method, however, a call to the Show method does
not establish an implicit owner-owned relationship. This means that
either form can be the currently active form.
Without an implicit owner-owned relationship, owner and owned forms
alike can be minimized, maximized, or moved. If the user closes any
form other than the main form, the most recently active form is
reactivated.
Although ShowDialog establishes an implicit owner-owned relationship,
there is no built-in way for the owned form to call back to or query
the form that opened it. In the modeless case, you can set the new
form's Owner property to establish the owner-owned relationship. As a
shortcut, you could pass the owner form as an argument to an overload
of the Show method, which also takes an IWin32Window parameter
(IWin32Window is implemented by Windows Forms UI objects that expose a
Win32 HWND property via the IWin32Window.Handle property).
The behavior of forms in an explicit modal owner-owned form
relationship is the same as its implicit modal counterpart, but the
modeless owner-owned relationship provides additional behavior in the
non-owner-owned modeless case. First, the modeless owned form always
appears on top of the owner form, even though either can be active.
This is useful when you need to keep a form, such as a floating tool
window, on top of other forms within an application. Second, if the
user presses Alt+Tab to switch from the owner, the owned forms follow
suit. To ensure that the user knows which form is the main form,
minimizing the owner hides the task bar buttons for all owned forms,
leaving only the owner's task bar button visible.
(c) "Windows Forms 2.0 Programming" by Chris Sells, Michael Weinhardt.
frm2.ShowDialog() make frm2 as a model dialog box, we can not click anywhere on form1 unless we close the instance of frm2.
frm2.show() there is no such restriction.

How to keep a window on top of all other windows in my application only?

I would like to display a status window in my C# Windows Forms application that informs the user when the application is waiting to acquire a lock. This is an application-defined thing, however, the window should be visible and always remain on top of all other windows of my application, even when the user clicks on another window (like for example the larger main window behind it).
It must not be modal (so ShowDialog() cannot be used) because the app needs to keep trying in the background and close the window automatically if the lock could eventually be acquired, and it really should not be top-most for the entire window station (i.e. all applications running in that terminal session).
I know the Form.TopMost property, but it can only bring and keep a single window above all others, even those from other applications. This is clearly not what I'm looking for.
I know that this is possible, I've seen it many times before in other applications. I just don't know how it can be done.
If you pass your main form into the Show method of the status form, it will stay on top of the main form, but not on top of other applications. So, in the main form you can have code like so:
StatusForm statusForm = new StatusForm();
statusForm.Show(this);
However, this will only point out one single window of your application as the owner.
You have to set the Owner property of the child form to the parent form, and use Show to show the child form.

Categories

Resources