I want my Windows Forms form to keep the window border, while having no title bar and being non-resizable (fixed) (similarly to window previews, when one hovers mouse over button on the taskbar):
Setting ControlBox to false and Text to "" removes the title bar and keeps the border as I want to, but the border is visible only if the form is sizeable. When I set the FormBorderStyle to one of the Fixed* styles, the border disappears:
How may I achieve the described behavior?
You can pinvoke SetWindowsLong and adjust window styles:
// run in LINQpad
private const int GWL_STYLE = -16;
private const int WS_SIZEBOX = 0x040000;
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
void Main()
{
var form = new Form();
form.ControlBox = false;
form.FormBorderStyle = FormBorderStyle.FixedDialog;
form.Show();
SetWindowLong(form.Handle, GWL_STYLE, GetWindowLong(form.Handle, GWL_STYLE) | WS_SIZEBOX);
}
After that you would have to prevent resizing manually though.
I just played around with a project of mine and set FormBorderStyle to FixedSingle through the Design view, and the window seems to keep the border for Windows 8. I initially had text in the title, which was forcing the border to render. I removed the text and the border no longer rendered, so as a hacky solution I just input an empty string, by hitting backspace a few times. This made the border show up and remain fixed.
Related
I'm trying to set childForm as the child of the main Excel window using the SetParent API through PInvoke:
Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
childForm.StartPosition = FormStartPosition.Manual;
childForm.Left = 0;
childForm.Top = 0;
As you can see above, my intention is also to position the child in the top left corner of Excel window. However, for some reason the childForm always ends up at some weird location.
What is it that I am doing wrong?
While all answers here suggest perfectly logical approaches, none of them worked for me. Then I tried MoveWindow. For some reason I don't understand, it did the job.
Here's the code:
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
...
Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
MoveWindow(childForm.Handle, 0, 0, childForm.Width, childForm.Height, true);
When using SetParent on a form that is currently a child of the desktop (in other words, one without a parent
set), you must set the WS_CHILD style and remove the WS_POPUP style. (See the Remarks section of the MSDN entry.) Windows requires that all owned windows have the WS_CHILD style set. This could also be causing the left and top properties to report/set the wrong values because the form doesn't know who it's daddy is. You can fix this by calling SetWindowLong after SetParent, but before you try to set the location:
//Remove WS_POPUP style and add WS_CHILD style
const UInt32 WS_POPUP = 0x80000000;
const UInt32 WS_CHILD = 0x40000000;
int style = GetWindowLong(this.Handle, GWL_STYLE);
style = (style & ~(WS_POPUP)) | WS_CHILD;
SetWindowLong(this.Handle, GWL_STYLE, style);
It depends on your ShowDialog call I believe. If you call ShowDialog without the parent paremeter, the parent is reset.
You could create a wrapper class that implements IWin32Window and returns the HWND to excel. Then you could pass that to the ShowDialog call of childForm.
You could also query the position of the excel application using GetWindowPos and then set the childForm accordingly.
Try a few things to diagnose the problem:
Put a breakpoint after setting Left
and Top, do Left and Top read zero?
Call SetParent last.
Make a method that sets Left and Top
again, and BeginInvoke the method.
Make sure your child window is really
the child. To do this call
ShowDialog, and try to click the
parent window. Make sure windows
prevents focus to the parent window.
Assuming you know how to get the hwnds of the windows you want to set z-order of, you can use this pInvoke:
public stati class WindowsApi
{
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
}
public class WindowZOrderPositioner
{
public void SetZOrder(IntPtr targetHwnd, IntPtr insertAfter)
{
IntPtr nextHwnd = IntPtr.Zero;
WindowsAPI.SetWindowPos(targetHwnd, insertAfter, 0, 0, 0, 0, SetWindowPosFlags.NoMove | SetWindowPosFlags.NoSize | SetWindowPosFlags.NoActivate);
}
I am able to set a windows position as topmost and also setting it no topmost with SetWindowPos. But i can't figure out how to check if a window is topmost or not. Is there any Method to check if a window is topmost or not with pinvoke?
You can use the GetWindowLong() function to check the Extended Window Styles.
Untested, but I believe it should work:
[DllImport("user32.dll", SetLastError=true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
const int GWL_EXSTYLE = -20;
const int WS_EX_TOPMOST = 0x0008;
public static bool IsWindowTopMost(IntPtr hWnd)
{
int exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
return (exStyle & WS_EX_TOPMOST) == WS_EX_TOPMOST;
}
Depending on the UI technology you*re using, you can choose of the following two:
Windows Forms: Form.TopMost
WPF: Window.TopMost
You can you those properties to check if a certain window is topmost and you can also use these to set a window topmost. I'd prefer these in favor of any win32 methods.
I have a WinForms application which uses four panels in one form to hold and show information, controls etc.. Those panels are hidden or shown depending on the button pressed on the form - I hope you get the idea :) The panels are transparent and the forms holds the background image.
Now to the problem - if the background of the form is an image the controls on a panel that changes it's state to shown need too much time too render - there is kind of a blink and you can see how the controls render one after another. Has anyone encountered this before?
ADDITIONAL INFO
the problem disappears when I fill the background with a solid color (not image!)
I already tried using different kinds of images (png, bmp, jpg, low res, small color palette etc. with no effect)
I really need the background image
I would really want to avoid converting to WPF - simply because I don't have too much time.
I will be grateful for any help.
add a panel on your form and Dock it to middle, Use your background image to this panel... and also try the following code
MainPanel.SuspendLayout();
panel1.Visible= true;
panel2.Visible= false;
MainPanel.ResumeLayout();
if your okay with win32 API,
solution 1)
[DllImport("user32.dll")]
public static extern bool LockWindowUpdate(IntPtr hWndLock);
on button click:
try
{
LockWindowUpdate(this.Handle);
//code here
}
finally
{
LockWindowUpdate(IntPtr.Zero);
}
solution 2) Use SendMessage() with WM_SETREDRAW (better one)
private const int WM_SETREDRAW = 0x000B;
private const int WM_USER = 0x400;
private const int EM_GETEVENTMASK = (WM_USER + 59);
private const int EM_SETEVENTMASK = (WM_USER + 69);
[DllImport("user32", CharSet = CharSet.Auto)]
private extern static IntPtr SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
IntPtr eventMask = IntPtr.Zero;
on button click:
try
{
// Stop redrawing:
SendMessage(panel1.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
// Stop sending of events:
eventMask = SendMessage(panel1.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
// code here
}
finally
{
// turn on events
SendMessage(panel1.Handle, EM_SETEVENTMASK, 0, eventMask);
// turn on redrawing
SendMessage(panel1.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
}
I am having a problem where my main form loses focus when opening a new form. I know I can revert the focus back by using mainForm.focus(), but how do I handle things if I want the main form to never give up its focus when new window is opened?
You can accomplish this by overriding the property ShowWithoutActivation in order for it to return true in the forms that you want to show without stealing focus from the form that shown it, in your case that would be your main form.
Cody Gray answered this, I'm just expanding it by directly pasting the code. Someone with edit rights can copy it over there and delete this for all I care ;)
pinvoke.net's ShowWindow method.:
private const int SW_SHOWNOACTIVATE = 4;
private const int HWND_TOPMOST = -1;
private const uint SWP_NOACTIVATE = 0x0010;
[DllImport("user32.dll", EntryPoint = "SetWindowPos")]
static extern bool SetWindowPos(
int hWnd, // window handle
int hWndInsertAfter, // placement-order handle
int X, // horizontal position
int Y, // vertical position
int cx, // width
int cy, // height
uint uFlags); // window positioning flags
[DllImport("user32.dll")]
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
static void ShowInactiveTopmost(Form frm)
{
ShowWindow(frm.Handle, SW_SHOWNOACTIVATE);
SetWindowPos(frm.Handle.ToInt32(), HWND_TOPMOST,frm.Left, frm.Top, frm.Width, frm.Height,SWP_NOACTIVATE);
frm.TopMost = false;
}
I'm trying to set childForm as the child of the main Excel window using the SetParent API through PInvoke:
Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
childForm.StartPosition = FormStartPosition.Manual;
childForm.Left = 0;
childForm.Top = 0;
As you can see above, my intention is also to position the child in the top left corner of Excel window. However, for some reason the childForm always ends up at some weird location.
What is it that I am doing wrong?
While all answers here suggest perfectly logical approaches, none of them worked for me. Then I tried MoveWindow. For some reason I don't understand, it did the job.
Here's the code:
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
...
Form childForm = new MyForm();
IntPtr excelHandle = (IntPtr) excelApplication.Hwnd;
SetParent(childForm.Handle, excelHandle);
MoveWindow(childForm.Handle, 0, 0, childForm.Width, childForm.Height, true);
When using SetParent on a form that is currently a child of the desktop (in other words, one without a parent
set), you must set the WS_CHILD style and remove the WS_POPUP style. (See the Remarks section of the MSDN entry.) Windows requires that all owned windows have the WS_CHILD style set. This could also be causing the left and top properties to report/set the wrong values because the form doesn't know who it's daddy is. You can fix this by calling SetWindowLong after SetParent, but before you try to set the location:
//Remove WS_POPUP style and add WS_CHILD style
const UInt32 WS_POPUP = 0x80000000;
const UInt32 WS_CHILD = 0x40000000;
int style = GetWindowLong(this.Handle, GWL_STYLE);
style = (style & ~(WS_POPUP)) | WS_CHILD;
SetWindowLong(this.Handle, GWL_STYLE, style);
It depends on your ShowDialog call I believe. If you call ShowDialog without the parent paremeter, the parent is reset.
You could create a wrapper class that implements IWin32Window and returns the HWND to excel. Then you could pass that to the ShowDialog call of childForm.
You could also query the position of the excel application using GetWindowPos and then set the childForm accordingly.
Try a few things to diagnose the problem:
Put a breakpoint after setting Left
and Top, do Left and Top read zero?
Call SetParent last.
Make a method that sets Left and Top
again, and BeginInvoke the method.
Make sure your child window is really
the child. To do this call
ShowDialog, and try to click the
parent window. Make sure windows
prevents focus to the parent window.
Assuming you know how to get the hwnds of the windows you want to set z-order of, you can use this pInvoke:
public stati class WindowsApi
{
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter,
int X, int Y, int cx, int cy, uint uFlags);
}
public class WindowZOrderPositioner
{
public void SetZOrder(IntPtr targetHwnd, IntPtr insertAfter)
{
IntPtr nextHwnd = IntPtr.Zero;
WindowsAPI.SetWindowPos(targetHwnd, insertAfter, 0, 0, 0, 0, SetWindowPosFlags.NoMove | SetWindowPosFlags.NoSize | SetWindowPosFlags.NoActivate);
}