How to hide/show the tool window but not close it - c#

I have a VS2010 Isolated Shell application and I have a tool window as below
public class MyWindow : ToolWindowPane
And this tool window supports multiple instance
[ProvideToolWindow(typeof (MyWindow ),
MultiInstances = true,
Style = VsDockStyle.MDI,
Transient = true)]
public sealed class MyVsxPackage : Package
Then in my application I can open more than one tool window (each tool window has its own window Id), but when I close one of them I just want to hide it, and next time when I reopen the window the settings on the window should keep the same before it was closed, how to handle this?
In another words, my question is: is there any way that prevent the multiple instance tool window from being closed by click the 'x' button (just hide it)?
Thanks in advance!

I supposed you have a list of toolbars with toolbars created in your App.
You must have a method in your toolbar that hides/show it. (If you don't really close toolbars, don't call close method).
When you "close" a toolbar call hide method, when reopen call show. (When close App, call close).
Hope this help you.

Related

Is this a way to show a modeless dialog from a dockable pane using WPF?

I'm building a Revit plugin. It consists of a dockable pane that (among other elements) has a button. I want to open a new, separate window when a user clicks this button.
At the moment, i create a new Window, but i don't know if that's the right way to go, because now i see two Revit icons on a task bar. I do not have experience as Revit user, i'm new to Revit development, so i'm not sure if this should be the case (two icons) and as silly as it sounds, i do not have admin rights to install random addins and get a feeling of expected user experience.
I create a Window using the following code:
ParametersMissingValueWindow parametersMissingValueWindow = new ParametersMissingValueWindow();
parametersMissingValueWindow.Show();
Based on the understanding of a dockable pane that i have, i think i do not want to create another dockable pane, but just a simple modeless dialog. I wasn't able to find any examples using WPF. Hence, any information whether this is the way to go or help on how to achieve this is highly appreciated.
The Show method takes an optional parent window argument. Specify the Revit main window as the parent window, and your modeless dialogue will be recognised as belonging to the running Revit process. It is accessible from the MainWindowHandle property.
var MyWindow = new MyWindow();
HwndSource hwndSource = HwndSource.FromHwnd(UIApplication.MainWindowHandle);
Window wnd = hwndSource.RootVisual as Window;
if (wnd != null)
{
MyWindow.Owner = wnd;
//MyWindow.ShowInTaskbar = false;
MyWindow.Show();
}
It's not necessary to assign a value to ShowInTaskbar property, but it actually achieves what i wanted to do from the beginning (have only one program open in taskbar), so i left it as part of the solution, but commentted out.
Big thanks to Jeremy Tammik for pointing out the parent property.
You can use WPF to setup a window to use in revit.
MyWPF menu = new menu();
System.Windows.Window wind = new System.Windows.Window();
wind.ShowDialog(); //--> the window shows up and make stuff for revit
if you need the menu to be a dockable one check this source.
Perhaps is not up to date and you will need to adapt the code to the new api.

Performance implications when hiding a window instead of closing it

I'm making a program that has a login window and the main window. I am wondering if hiding windows would have more impact on performance than closing them.
I've written down both these options, let me know if there's a better way to do it.
private void Login()
{
DataMatrixWindow dmWindow = new DataMatrixWindow(); // Creates new Datamatrix window
dmWindow.Show();
Close(); // Closes login window
}
Or keeping Login window alive the whole time, and just show / hide it when needed.
private void Login()
{
DataMatrixWindow dmWindow = new DataMatrixWindow(); // Creates new Datamatrix window
dmWindow.Show();
Visibility = Visibility.Collapsed; // Hides login window
}
MSDN makes no note of a potential performance hit if windows are not closed.
Window.Close Method: Unmanaged resources created by the Window
are disposed.
Window.Closing Event: If you want to show and hide a window multiple
times during the lifetime of an application, and you don't want to
re-instantiate the window each time you show it, you can handle the
Closing event, cancel it, and call the Hide method. Then, you can call
Show on the same instance to re-open it.
Some more details
I am closing and creating a new Datamatrix window, though the same arguments could be made whether to show or hide it like the login screen
I do not expect the user to constantly log in and out, so these switches shouldn't occur very often (Hence why I'm leaning to closing the login window instead of hiding it)
When you use Visibility.Collapsed, it does not remove your window from the visual tree, therefore there is performance implication on leaving it unseen.
To see this performance implications yourself you can do 2 things:
Open Snoop and you will be able to see the entire window on the visual tree.
Create a tester and fill it with buttons (for example) through code - place 10 thousand and set them with Visibility.Collapsed. Then check the performance there as apposed to a clean application. see how long does it take for it to show when starting the exe.
Hope this helps.
I am wondering if hiding windows would have more impact on performance than closing them.
Probably. Closing and showing a simple window such as a login form shouldn't impact the performance noticeably so I would recommend you to close the window when you have logged in and show another instance of it when and if you need to log in again. This is certainly better than keeping the window open in the background after you have logged in. At least in my opinion.

Window manipulation and inctences control

In my application there are only 2 windows — win_a & win_b, on each of these windows there is button that call another window, e.g. click on btn1 of win_a will call win_b, click on btn2 of win_b will show win_a.
Desired behaviour:
1. Only one instance of object is premitted at the same time, e.g. situation, where 2 instances of win_a running at the same time is not permitted.
When you click on button that calls windows that already exist this action will only change a focus to needed window.
If you call a window that previously had been created, but after this has been closed this action will create a new instance of this window. E.g. there are 2 running windows. you close one of them and after try to call this window back, so related button will create it.
How to write it in WPF (XAML + C#). For the moment I wrote a version that can create a lot of instances of the same window (no number of instances control implemented), but I want to see only one instance of the same window, as we can see it in a lot of applications.
Example of my code:
Window win = new Window();
win.Show();
Thanks.
first you need 2 references on each other window. on button click
you need to check one reference.
say in win_a
//win_b is a member on Windows_a class
if(_win_b.IsVisible())
{
// set focus on it
}
else
{
//show win_b
}
make the same for windows_b
I would suggest a different approach:
make a singleton class, that holds a list of tuples List>
when creating windows you can check if the window is in the collection or not.
if the collection holds a window you can set it activ win.Activate(),
else you can create it and add a reference to the collection list.add(tuple(win,"windowA"))
3.finally on the windows that you can add to the collection, on closing you need to remove the window from the singletons list, you can do this handling the Close event of the window
i don't have the code i wrote here, but i hope it helps.

WPF owner window on top of child window

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 acti­vation/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();
}
}
}

Should Form.ShowDialog(IWin32Window) work with any window handle?

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)

Categories