I would like to open the help dialog. I'm using this call:
public static void ShowHelp(Control parent, string url);
I'm launching it through a class that doesn't have access to the main control. So I'm passing null as the parent. It does seems to work but I want to make sure I'm not missing anything.
what does this "parent" argument stands for? what does .net do with it?
Is it safe to pass null as this argument?
I did notice in .Net source code this switch:
if (parent != null) {
handle = new HandleRef(parent, parent.Handle);
}
else {
handle = new HandleRef(null, UnsafeNativeMethods.GetActiveWindow());
}
Does it safe that it's using the "UnsafeNativeMethods" ?
The Parent control determines which window will own the dialog. If the parent is not a window, the ultimate parent (which should be a window) of this control will be used. If the parent parameter is null, the main window of the process will be chosen (if there is one).
This is needed so that the dialog can be modal and interaction with the parent window is blocked until the dialog has been dismissed.
Related
Our Application is displaying an "update-hint", if a new version is available.
This Update-hint should be "topmost" within the application, but, if the application is minimized, or send to the background, the update-hint should vanish as well..
Just using
this.TopMost = true;
will overlay "ANY" application that is currently running...
Is there a way to just "overlay" windows generated by the current application?
Desired:
application shows update-hint on top of every window, while application is in the foreground. Switching to another application will also send the update-hint to the background.
Desired: Update-Hint overlays ANY window of the current application:
Not desired: Update-Hint overlays FOREIGN applications as well:
Despite the name of the property, TopMost is actually your enemy here. To make a "floating form" stay above a main form, without obscuring other applications when they get focus, try it this way:
FormX f = new FormX();
f.Show(this);
"this" in this example, is the main form instance. It means the form you created is now owned by the main form, and will make it float above it. You get the added benefit of, when minimizing the main form, the floating forms will disappear, too.
I figured out a way to solve it.
Setting the owner of the UpdateHint is required, but in order to keep it on top of every application window, one has to change the owner, if a new Window is either shown, or activated.
Within our application, every Form is inheriting InterceptorForm, so all I had to do was to modify the InterceptorForm accordingly:
Change the Owner to this, except if there is no dialog, or this is the dialog itself:
public class InterceptorForm : Form
{
protected override void OnLoad(EventArgs e)
{
...
if (this.GetType() != typeof(UpdateHint) && MainWindow.updateHint != null)
{
Log.t("Setting owner on update hint during onload: " + this.GetType());
MainWindow.updateHint.Owner = this;
}
base.OnLoad(e);
}
and
protected override void OnActivated(EventArgs e)
{
if (this.GetType() != typeof(UpdateHint) && MainWindow.updateHint != null)
{
Log.t("Setting owner on update hint: " + this.GetType());
MainWindow.updateHint.Owner = this;
}
base.OnActivated(e);
}
}
The UpdateHint now stays on top of every window belonging to our application, but can be overlayed by any other application.
In WinForms I need to ensure that newly opened Form is on top of the stack and does not hide behind Form that instantiated it. I do not want to use TopMost property as it forces new form to stay on top of all Forms opened by all running processes. I just need to have my new Form to open on top of all forms in current application.
This method will check the current application OpenForms collection for a window with a title you pass in. It will activate the window if it is found, or have the window manager launch one.
Not sure how you plan on Z-Ordering your windows, but you could use the loop in the code and do something with each openform.
public void FindWindowOrMake(string theTitle)
{
var found = false;
foreach (var openForm in Application.OpenForms.Cast<Form>()
.Where(openForm => openForm.Text.Equals(theTitle)))
{
found = true;
openForm.Activate();
break;
}
if (found) return; // target found and activated
// create new instance
WinMgr.Create(theTitle);
}
I want create using C# window with setted parent to my defined handle,
this is a other process window handle.
Anyone know how to do this?
Greetings,
If I understood your question correctly you should be able to achieve what you want by using something like this:
class Win32Window : IWin32Window
{
IntPtr handle;
public Win32Window(IntPtr handle) { this.handle = handle; }
public IntPtr Handle
{
get { return this.handle; }
}
}
static void Main()
{
IntPtr targetParent = // Get handle to the parent window
new MainForm().ShowDialog(new Win32Window(targetParent));
}
This will turn MainForm a child window of the specified window making it always appear above it. I use ShowDialog in the example, but this should also work for Show. This is specific for Windows Forms.
In WPF you can try the following:
var helper = new WindowInteropHelper(/* your Window instance */);
helper.Owner = // Set with handle for the parent
I quickly tried this after showing the WPF window and it seemed to work as expected, but WPF knowledge is not that great.
I believe the Handle will be read-only; therefore, the .Parent property is read-only. However, the .Owner property has a getter and a setter (ref. MSDN) ... however, you must have a reference to the Parent window.
Without more information, I will not be able to provide much more than that.
If your parent candidate is an unmanaged Window, check this link.
Is it possible for Owner window in WPF be on top of Child window when you click on it while Owner window is below Child window?
here is example how I call child window:
Window2 window = new Window2();
window.Owner = this;
window.Show();
Parent/Owner window will always be under child window.
To get the behavior you want, you don't want to set the Owner on either window.
You, of course will have to handle the logic yourself when closing either of the windows to close your imaginary "child" window.
There may be some other logic you'll have to implement related to minimizing, maximizing, etc.
Many of the answers on this page involve nulling-out the Window.Owner property for some or all of the (non-MainWindow) windows in your System.Windows.Application. While this is a simple and easy fix that does indeed, in isolation, fix the issue of Window overlap, unfortunately it also inhibits a lot of useful application-wide functionality that WPF seems otherwise eager to provide in the areas of:
Application activation/deactivation (via mouse-click, desktop Alt-Tab switching, etc...),
correct observance of the Application.ShutdownMode property, and generally,
orderly cleanup, resource disposal, and exit of your Application upon shutdown.
It is possible fix the Window overlap issue while still preserving these system-wide WPF features by instead designating a special invisible window instance as your Application.MainWindow.
Modify your application so that the first Window it creates--which is the Window that gets assigned to Application.MainWindow--is a special dummy Window that is then made invisible by setting its Visibility to Visibility.Hidden or calling Window.Hide(). This will not hide its owned windows. Then, ensure that your desired "main" window containing your true content, plus all the other windows, owned by this invisible window.
Once hidden, the dummy Window will not show in the Windows 10 taskbar. You can set the Window.ShowInTaskbar property on whichever of the visible windows you deem appropriate to simulate apparent special designation, as required.
This approach allows any of the visible windows in your Application to be on top of the others, while still preserving WPF features and behaviors for system-wide app activation. For example, when the Application is activated (by clicking on any one of the windows, or via Alt-tab), all of the application's windows are together brought above any other desktop app windows, while still preserving the most recent "in-app" Z-order. WPF shutdown functionality is also preserved, including correct observation of the Application.ShutdownMode logic in accordance with the invisible MainWindow (or all the others) being closed.
I ran into a similar situation. I solved this by simply removing the owner after showing the window.
Window2 window = new Window2();
window.Owner = this;
window.Show();
window.Owner = null;
Edit:
Someone replied to this, and while looking at it, I decided I wanted to make an extension method.
public static void ShowAsIfChildOf(this Window childWindow, Window parentWindow)
{
childWindow.Owner = parentWindow;
childWindow.Show();
childWindow.Owner = null;
}
Please note that the solution mentioned by Licht
Window2 window = new Window2();
window.Owner = this;
window.Show();
window.Owner = null;
seems to me to be the same as
Window2 window = new Window2();
window.Show();
i.e., as if no ownership relationship has been set, i.e., when you close the owner window the owned windows do not close, etc., and may not be a solution when one would wish to have all of the ownership relationship features except "An owner window can never cover an owned window."
Once this relationship is established, the following behaviours are exhibited:
If an owner window is minimized, all its owned windows are minimized as well.
If an owned window is minimized, its owner is not minimized.
If an owner window is maximized, both the owner window and its owned windows are restored.
An owner window can never cover an owned window.
Owned windows that were not opened using ShowDialog are not modal. The user can still interact with the owner window.
If you close an owner window, its owned windows are also closed.
The best solution here looks to me to be the one with hidden main dummy window described by Glenn Slayden, at the link below, though it would be nice if there was a simpler one.
https://stackoverflow.com/a/66110288/19683309
Don't set Owner for child window, then in MainWindow handle OnClosing event like this:
private void MainWindow_OnClosing(object? sender, CancelEventArgs e)
{
foreach (var window in Application.Current.Windows)
{
if (window is Window appWindow)
{
if(appWindow.Equals(Application.Current.MainWindow))
continue;
appWindow.Close();
}
}
}
When using System.Windows.Forms.ShowDialog(IWin32Window), should I be able to pass in an IWin32Window representing any window handle and have it be modal with respect to that window?
As part of an Internet Explorer 7 extension I'm trying to open a window modal with respect to an Internet Explorer tab. It's not the currently selected tab, but I can get the hwnd of the tab OK. However, when I pass this to ShowDialog my Form is shown, but it's not modal with respect to anything: I can still do things in Internet Explorer, including in the tab that's supposed to be the owner. My form is shown floating above the Internet Explorer windows and it stays on top, so it's not like it's just opened as a normal form, but it's not correctly modal.
Using Spy++, I can find my form and it's owner handle is correctly set.
Does this mean that something has gone wrong, or I'm doing something wrong? How do I make my form correctly modal?
FYI, I'm using this wrapper class to create an IWin32Window from a hwnd (thanks Ryan!):
/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
public WindowWrapper(IntPtr handle)
{
_hwnd = handle;
}
public IntPtr Handle
{
get { return _hwnd; }
}
private IntPtr _hwnd;
}
UPDATE: Using Internet Explorer 7 & .NET 2.0
UPDATE: Playing around some more with Spy++ and the handles it exposes, I find that if I use a different hwnd then I can make my window modal to the tab:
I was using the tab's hwnd as suggested by the IWebBrowser2.HWND doc, which in Spy++ appears as class TabWindowClass. It has a child of class Shell DocObject View, which has a child of Internet_Explorer_Server. If I use the hwnd of the Internet Explorer_Server then it works correctly, for example, when I click with the mouse on other tabs, Internet Explorer reacts normally. When I click with the mouse on the tab of interest, it plays the windows d'oh sound and doesn't do anything.
I don't yet know how to programatically get the Internet_Explorer_Server hwnd, but it should be possible.
Also, for what it's worth, while playing with other window handles I was generally able to make my form modal to other applications and dialogs. So I guess the answer to my question is 'many but not all handles'... possibly it depends on the application?
UPDATE: Another side-note: The original reason I wanted to make my form modal to the tab instead of the whole window is that when opening a MessageBox from my form, passing the form as owner, the MessageBox would not always open on top of my form. If a new Internet Explorer tab had just been opened but wasn't active then the MessageBox would be hidden and that tab would start flashing. However, since Internet Explorer was disabled with my form opened modal it wasn't possible to switch to that tab, so Internet Explorer would be frozen. I thought that opening my form modal to the tab would solve this, but I've found another solution is to avoid using MessageBox: if I use a second form and ShowDialog(this) from my first form then the second form correctly opens to the front. So it seems that Form.ShowDialog() works better than MessageBox.Show() in some cases. More discussion in Problems with modal dialogs and messageboxes.
ShowDialog() does two important things. It starts pumping a message loop so it acts modally to the calling code. And it disables any other windows in the application with a EnableWindow(false) API call. The latter is what is not happening in your case. Not entirely surprising, considering that the window that needs to be disabled is not a WF window.
You may need to call EnableWindow() yourself. Be sure to re-enable it in before the dialog closes or Windows will go hunting for another app's window to give the focus to.
Your code is correct. The problem you are likely running into though is that IE has a threading model related to its tabs. I don't know the exact details but the short version is that each tab can and likely is running on a different thread than other tabs.
The Modal'ness of a dialog is specific to the thread where the dialog is running. UI on other threads will be unaffected by a model dialog on another thread. It's entirely possible you are able to access tabs which are running on a different thread for this reason.
Here's a more concise version of Ryan/Rory's WindowWrapper code:
internal class WindowWrapper : IWin32Window
{
public IntPtr Handle { get; private set; }
public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
}
I have never tried this from an IE extension, but I have a hunch that IE may not "respect" a Win32-style modal window the same way it does a modal window raised from Javascript using window.open().
Have you tested this code against something other than IE, just to confirm it works the way it should for other applications?
here is a build in solution in .NET:
public static NativeWindow FromHandle(IntPtr handle)