I'm very new to C# and still trying to get my head round it (with help of some very patient friends).
I have an issue with setting a new windows form's TopMost property to true. I have two (almost) identical forms; 1 which works OK and one which doesn't.
Both of the forms have the TopMost property set to true.
Form1 shows the window and when I try to click behind it, the form flashes a few times and issues a windows beep.
Form2 also shows the form but when I click behind it, the form greys out (or loses focus) and I can click away on the main form.
I've searched for an answer to this issue and found an answer which suggested putting this.TopMost = true; in the form's load event but that didn't work.
The only thing I have changed which may or may not have had an effect is that Form1 was created with .NET 4.5 set in the properties and before creating Form2, I changed this to .NET 3.5 (client profile). I've tried changing it back but it hasn't helped. Before I delete and create Form2 again, does anyone have any ideas?
Many thanks in advance.
(If you need any more information, please just let me know)
TopMost is a property that is used to make sure one window is always shown above all others within an application. Microsofts example was a find and replace tool.
The difference you are finding is that Form1 was created as a modal dialog through the use of ShowDialog. Show dialog makes sure that your form must be closed before all other windows in the application can be used again. For example; using a form to gain user data to enter into a parent forms database.
Show is used when you don't mind if your user has finished with their dialog or not, such as allowing your user the chance to use some utility (e.g timer, stopwatch) that will assist within the main function of a program.
The only visual difference I can think of when using different .Net frameworks, is different windows dialogs such as the OpenFileDialog, that have been updated throughout the framework
It may help you;
frm.TopLevel = true;
frm.TopMost = true;
This link from Microsoft confirm that could be a Bug in Windows 7 and Windows Server 2008 R2 I've faced it in a Windows 7 Embedded system and the provided patch fix the problem so please consider to take a look :)
http://support.microsoft.com/kb/2587473/en-us
Hope it help!
The DIY-way to do it - works 100%!
public static class User32
{
public const int SW_HIDE = 0;
public const int SW_SHOW = 5;
public const int SW_SHOWNORMAL = 1;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool AllowSetForegroundWindow(uint dwProcessId);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
User32.AllowSetForegroundWindow((uint)Process.GetCurrentProcess().Id);
User32.SetForegroundWindow(Handle);
User32.ShowWindow(Handle, User32.SW_SHOWNORMAL);
I hat a similar problem in my solution. After using the overloaded Show-function it worked:
frm.TopLevel = true;
frm.TopMost = true;
frm.Show(this)
Add the following code in the Shown event:
this.TopMost = true;
this.Focus();
this.TopMost = true;
Related
I'm looking for some guidance here, if not an example of how to accomplish what I am looking to do in C-Sharp(C#).
There is a particular button on a MS Access Ribbon that I would like to click. The MS Access window has a custom UI and custom buttons in different groups. When the button in the first group is clicked, it then opens a childform window. I need to automate that particular step and have my C# application programmatically open that child form by clicking the button or any other means to get it open.
I attempted to do this with the SendKeys and FindWindow functions, but this prove to be rather faulty, because the ALT id's kept changing in MS Access and the SendKeys would stop working.
I've tried searching for articles that would help me with this issue, but all I came across are tutorials on how to make a custom add-in for MS ribbon (I do not want this).
There might be a better way to do this and any help with it is greatly appreciated!
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string strClassName, int nptWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Public Void SendTest()
{
IntPtr WinHandle = FindWindow("OMain", 0); // OMain = Window Class --found window by class
if (WinHandle == IntPtr.Zero)
{
MessageBox.Show("Program is not running or could not be detected.");
return;
}
SetForegroundWindow(WinHandle);
SendKeys.SendWait("%"); // ALT
SendKeys.SendWait("Y1"); // Y1
SendKeys.SendWait("Y1"); //Y1
}
I'm working on an application that should do the following on start-up:
Connect to an external application using COM (AutoCAD).
Send message to the application to run some DLL code (opens a window).
Hide AutoCAD's window, but keep the DLL's window visible.
I've successfully completed the first 2 steps, but the third is giving me some issues.
I do not know if it is possible to make a child window visible while it's parent is not visible. Every time that I make the child visible or make it the top most window, AutoCAD becomes visible as well.
My objective is to run my DLL code, but keep AutoCAD running in the background, completely invisible to my users. The DLL must be loaded, through AutoCAD, because it allows me to work with AutoCAD's .NET interface as opposed to COM.
In any case, I'm curious if what I'm trying to do is possible, perhaps through some Windows API calls or perhaps something in .NET.
PS: I'm unsure if this window relationship is really a parent-child one. I'm assuming it is though because my window belongs to the AutoCAD application instance due to the DLL loading.
Any help is greatly appreciated. Thanks! :)
EDIT:
DLL Code to create a window.
//CommandMethod is an AutoCAD attribute for entering into the DLL. This code is called
//when the user attempts the command "AUTOCADCOMMANDNAME" or can be done by simulating
//the command programmatically.
[CommandMethod("AUTOCADCOMMANDNAME", CommandFlags.Session)]
public void CommandEntry()
{
MainWindow mainWin = new MainWindow();
mainWin.ShowDialog();
}
Main Application Code
public static void Main()
{ //Use a utility class to create a connection to AutoCAD via COM
AcadApplication acadApp = ACUtil.GetAcadInstance(out createdNewInstance);
acadApp.Visible = false;
//Irrelevant code omitted...
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
acadApp.Quit(); //Exit AutoCAD application
//Note: doesn't quit until mainWin closes because of ShowDialog()
}
Can't be done. Parent windows control child window visibility.
Your best alternative is to make the DLL window a top-level window (but owned by the AutoCAD window).
Note that the DLL window will still be part of the AutoCAD thread.
What you want can be achieved, despite what others may think. You just need to think about the problem in a different way. Don't think about parent and child Windows... instead, think about a splash screen Window.
Typically, splash screens appear before the main application Window, but does that make them the parent? No, it doesn't. Normally, they'd be closed after the main Window has opened, but there is no reason why you couldn't hide it instead of closing it.
To find out how to do this in WPF, please refer to my answer from the How to open a child Window like a splash screen before MainWindow in WPF? question, here on Stack Overflow. Extending that answer a little bit, I should point out that you won't need to use a Timer. Instead of the code from the linked page, you could do something like this:
private void OpenMainWindow()
{
autoCadWindow.Visiblity = Visibility.Collapsed;
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
Haha! I found it!
So, I ended up calling the SetWindowPos function in the Windows API and supplied the handle for AutoCAD window. I did this inside my main application:
[DllImport("User32.dll")]
static extern bool SetWindowPos(IntPtr hwnd, IntPtr hwndInsertAfter, int x, int y, int w, int h, uint flags);
public const int SWP_HIDEWINDOW = 0x0080;
public static void Main()
{
//...Setup AutoCAD...
//Change window size and hide it before calling to open mainWin inside the DLL.
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
//Display mainWin by entering the DLL.
acadApp.ActiveDocument.SendCommand("AUTOCADCOMMANDNAME");
//Terminate application as before...
}
Basically I'm telling the AutoCAD window to hide by modifying the HWND directly. I also set the dimensions to width=0 and height=0 which causes the window to take up the minimum size possible. Unfortunately, the window will flicker once, but for my purposes, that is negligible. If anyone can find a way to remove the flicker, that would be great! :)
EDIT: When using SetWindowPos, Windows tends to remember the values entered for the next time that application window is shown. This means that if not restored properly, then the next time the user opens AutoCAD manually, it will have the coordinates of 0,0 and the minimum width/height.
To change that behavior, it is necessary to obtain the window information. For my program, I used GetWindowRect obtain the original settings. Before closing my program, I restored those settings using SetWindowPos. See the code below for details:
First, import necessary WINAPI functions and structs:
[DllImport("User32.dll")]
static extern bool GetWindowRect(IntPtr hwnd, out RECT rect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
Obtain original settings before modifying window:
RECT originalRect;
GetWindowRect(new IntPtr(acadApp.HWND), out originalRect);
Modify the window to hide (and resize):
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1), 0, 0, 0, 0, SWP_HIDEWINDOW);
Restore original settings before quitting:
SetWindowPos(new IntPtr(acadApp.HWND), new IntPtr(1),
originalRect.Left,
originalRect.Top,
originalRect.Right - originalRect.Left,
originalRect.Bottom - originalRect.Top, 0);
I am using the following to Show/Hide window by its handle:
[DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
// Win32 API Constants for ShowWindowAsync()
private const int SW_HIDE = 0;
private const int SW_SHOW = 5;
ShowWindowAsync(_hWnd, SW_SHOW); //Show Window
ShowWindowAsync(_hWnd, SW_HIDE); //Hide Window
When I hide Sticky Notes and then Show them again it cause visual "holes" in the stickies and I have to close the Sticky Notes and reopen.
Here's a screenshot of the problem:
I believe the problem is specific to the Sticky Notes.
I dont know why it happens but I would like to solve it somehow..
I thought about checking if the window is Sticky Notes, and if it is then Open/Close it instead of Show/Hide will act the same but I dont really like it - feels hacky.
Changing from ShowWindowAsync() to ShowWindow() solved the problem.
I dont know why the ShowWindowAsync() cause this problem and I wish for an educating answer here but for now, as long as my problem is solved I am happy.
I am making excel add-in in which clicking on menu item or toolbar button, Form opened. I have set form's topmost to true but it remain topmost to all applications of windows xp. I just need to remain topmost to Microsoft Excel only.
I have choosed project in Visual Studio 2008, in Excel ->2003.
Please tell me how to do that with any way ........
You can set your Form's owner to be the Microsoft Excel window. In Windows owned windows are always displayed above their owner. Dialogs and things like the search box in Excel are owned windows, which is what keeps them displayed above their owner.
There are a couple of ways you can set a Form's parent:
The Form.Owner property (although the owner has to be another form)
Use the Form.Show(IWin32Window owner) overload. (See this blog post for how translate an window handle to an IWin32Window).
Use SetWindowLong() with the GWLP_HWNDPARENT parameter.
Use ShowDialog() as Mikael Svenson suggested.
This does require you to know the Excel applications window handle.
[Edit - changed code]
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
void func()
{
Form1 f = new Form1();
SetParent(f.Handle, (IntPtr)ThisAddIn.ExcelApplication.Hwnd);
f.Show();
}
How can I refer to active Window of WPF application in C#, using something like ActiveForm property in WinForms?
One possible way would be to scan the list of open windows in the application and check which one of them has IsActive = true:
Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
Not sure if there may be more than one active window if, for example, there's a modal dialog showing, in which case, the owner of the dialog and the dialog itself might be active.
There is better way to do this using PInvoke. Aviads answer is not working all the time (there are some edge cases with dialogs).
IntPtr active = GetActiveWindow();
ActiveWindow = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);
One must include following import first:
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
I know this is a bit old question but I think my answer could help someone.
My problem was this: I had a WPF MVVM application and I needed to get my MainWindow instance in the second view, i.e. second view model, in order to set the visibility of title bar button to visible.
This is my solution:
MainWindow window = (MyApp.MainWindow)App.Current.MainWindow;
window.btnSearch.Visibility = System.Windows.Visibility.Visible;
Hope this would help someone.
I have problems With this way "Application.Current.Windows.OfType().SingleOrDefault(x => x.IsActive);" specialy because I was building an aplication with a main Window then i had problems when the main window was selected. I resolve it creating this:
In some base class or App.xaml.cs create this:
public static Window ActivatedWindow {get;set;}
Then put in your base class deriving Window or all of your Window's Activate Event:
First Option - personal Window Base Class:
public class MetroToolWindowBase
{
public MetroToolWindowBase()
{
Activated += new EventHandler(MakeActive);
}
private void MakeActive(object sender, EventArgs e)
{
App.ActivatedWindow= this;
}
}
Second Option- In Activated Event of Windows:
private void XWindow_Activated(object sender,EventArgs e)
{
App.ActivatedWindow= this;
}
Another way to do it is to use the native GetActiveWindow function from user32.dll.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetActiveWindow();
To convert it to an actual WPF Window:
IntPtr handle = GetActiveWindow();
HwndSource hwndSource = HwndSource.FromHwnd(handle);
var window = hwndSource?.RootVisual as Window;
If hosting a WPF Window in a WinForms app, WindowInteropHelper should be used. This makes for example the Window owner work correctly:
var wih = new WindowInteropHelper(window)
{
Owner = GetActiveWindow()
};
I edited my old answer because the edge case I encountered disappeared after a Visual Studio update, but it can be checked from answer history. I encountered an issue there where I was getting null for active window in certain circumstances while debugging.