I've created a custom layered WPF window with the following properties:
AllowsTransparency = True
ShowInTaskbar = False
Background = Transparent
Topmost = True
Icon = "Icon.ico"
I've added Icon.ico under "Project Properties"->"Application" tab.
The icon displays as the default WPF window icon if ShowInTaskBar is false, but displays correctly if ShowInTaskbar is true.
We want the icon to show up correctly in the Alt+Tab menu. How can we achieve this and have ShowInTaskbar = False?
There are several problems here. First of all, when ShowInTaskbar property is set to false, an invisible window gets created and assigned as a parent of current window. This invisible window's icon is displayed when switching between windows.
You can catch that window with Interop and set it's icon like this:
private void Window_Loaded(object sender, RoutedEventArgs e) {
SetParentIcon();
}
private void SetParentIcon() {
WindowInteropHelper ih = new WindowInteropHelper(this);
if(this.Owner == null && ih.Owner != IntPtr.Zero) { //We've found the invisible window
System.Drawing.Icon icon = new System.Drawing.Icon("ApplicationIcon.ico");
SendMessage(ih.Owner, 0x80 /*WM_SETICON*/, (IntPtr)1 /*ICON_LARGE*/, icon.Handle); //Change invisible window's icon
}
}
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
The other problems for you to think about would be:
Find out what happens when ShowInTaskbar property changes at runtime;
Extract an icon from your window rather than from file;
Related
I have a requirement to override the Minimize function of the Telerik radWindow (clicking the Minimize Button on the Title Bar). Instead of the Window Minimizing to the bottom left of the screen I intend to simply reduce the Height of the Window leaving just the Title Bar showing (in the original position). Restoring the Window will again simply set the Height back to its original value to expand the Window….
So, I need to set Handle = true when the SC_MINIMIZE Message is received, this will prevent the Window from minimizing, then i can implement my own code to change the Height of the Window… This is the code so far…
private void RadWindow_HostCreated(object sender, HostWindowCreatedEventArgs e)
{
e.HostWindow.SourceInitialized += HostWindow_SourceInitialized;
}
private void HostWindow_SourceInitialized(object sender, EventArgs e)
{
var source = PresentationSource.FromVisual((Window)sender) as HwndSource;
if (source != null) source.AddHook(new HwndSourceHook(HandleMessages));
}
private IntPtr HandleMessages(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// 0x0112 == WM_SYSCOMMAND, 'Window' command message.
// 0xF020 == SC_MINIMIZE, command to minimize the window.
if (msg == 0x0112 && ((int)wParam & 0xFFF0) == 0xF020)
{
handled = true; // not catching SC_MINIMIZE here
}
return IntPtr.Zero;
}
However, while I seem to be catching Windows Messages in the HandleMessages function, it is not setting handled = true; when I click the Minimize Button…
Any help would be appreciated…
I am developing a Windows Forms application in C# in which I have a form which must start in a maximized state and not allow users to restore or resize it. I have already configured the form to start in maximized mode, disable the restore and maximize button and locked the borders of the form but when the title bar is double clicked, the form restores to a smaller size which is unexpected. The following are the properties I set to achieve the required behaviour:
FormBorderStyle = FixedSingle
MaximizeBox = False
WindowState = Maximized
Can someone please help me solve this problem and explain me the solution?
Thanks in advance.
You have to remember that your form starts with some default size values and double click is just toggling between 2 states.
Within your normal state the form will retrieve it's last ( in your case default ) size which you can override :
Width = Screen.PrimaryScreen.Bounds.Width;
Height = Screen.PrimaryScreen.Bounds.Height;
Another thing is that your application has something called start position which ( from what I remember ) defaults to the center of the screen and you can change it using :
Form.StartPosition = new Point(0, 0); // top-left corner
Now all you have to do in your applicaiton is to check for the toggle between window states. Easiest way would be to use WndProc and wait for messages listed in this msdn page :
protected override void WndProc(ref Message m)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MAXIMIZE = 0xF030;
const int SC_RESTORE = 0xF120;
if (m.Msg == WM_SYSCOMMAND)
{
switch((int)m.WParam)
{
case SC_RESTORE:
// your window was restored ( double clicked on the command bar )
// set it's window state back to maximize or do whatever
break;
case SC_MAXIMIZE:
// your window was maximized .. no actions needed, just for debugging purpose
break;
}
}
base.WndProc(ref m);
}
This can be accomplished by catching the event and overriding it:
private void Form_Load(object sender, EventArgs e)
{
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.WindowState = FormWindowState.Maximized;
this.MaximizeBox = false;
this.MinimumSize = Screen.GetWorkingArea(this.Location).Size;
}
private const int WM_NCLBUTTONDBLCLK = 0x00A3;
//double click on a title bar
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCLBUTTONDBLCLK)
{
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);
}
I need to add scroll horizontal and vertical scroll bar. The problem is that they doesn't work, as in when I use them the screen doesn't move.
VScrollBar vScrollBar1 = new VScrollBar();
HScrollBar hScrollBar1 = new HScrollBar();
vScrollBar1.Dock = DockStyle.Left;
hScrollBar1.Dock = DockStyle.Bottom;
Controls.Add(vScrollBar1);
Controls.Add(hScrollBar1);
I use the code to add scroll bars, how do I activate them or get them to work as I need?
Thanks!
You usually don't add Scrollbars; you set AutoScroll = true in the form's property panel.
Now when any control grows out of the Form or is moved over right or bottom border the Form will show the necessary Scrollbar.
You can test it with a Label and a TextBox: Set the Label to the right border and script the TextBox's TextChanged event like this:
private void textBox1_TextChanged(object sender, EventArgs e)
{
label1.Text = textBox1.Text;
}
Now run the programm and enter stuff into the Textbox; you will observe how the Label grows and how the Form brings up a horizontal Scrollbar when it goes over the edge.
Note 1: This will not work if the Form has AutoSize = true - then instead the form will grow! If the Form has both AutoSize and AutoScroll true, then AutoSize will win.
Note 2: This test will only work if the Label has AutoSize = true, as it has by default..
You need to use the Panel control as container of your child controls and set "AutoScroll" property to true.
Set true to AutoScroll property of Form.
Write this code in your Form Load Event, and you will get your scroll bar, like I am writing it here in my Form Load Event.
private void Form1_Load(object sender, EventArgs e)
{
Panel my_panel = new Panel();
VScrollBar vScroller = new VScrollBar();
vScroller.Dock = DockStyle.Right;
vScroller.Width = 30;
vScroller.Height = 200;
vScroller.Name = "VScrollBar1";
my_panel.Controls.Add(vScroller);
}
vScrollbars and hScrollbars are just plain controls without code. [UI]
You need to code to make them do something!
Or just set the property 'AutoScroll = true;' in your form or add a panel and set it to true.
However your control needs Focus() to scroll with your mouse wheel.
Here is a little workaround:
public Main()
{
InitializeComponent();
//Works for panels, richtextboxes, 3rd party etc..
Application.AddMessageFilter(new ScrollableControls(panel1, richtextbox1, radScrollablePanel1.PanelContainer));
}
ScrollableControls.cs:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
//Let controls scroll without Focus();
namespace YOURNAMESPACE
{
internal struct ScrollableControls : IMessageFilter
{
private const int WmMousewheel = 0x020A;
private readonly Control[] _controls;
public ScrollableControls(params Control[] controls)
{
_controls = controls;
}
bool IMessageFilter.PreFilterMessage(ref Message m)
{
if (m.Msg != WmMousewheel) return false;
foreach (var item in _controls)
{
ScrollControl(item, ref m);
}
return false;
}
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
private static void ScrollControl(Control control, ref Message m)
{
if (control.RectangleToScreen(control.ClientRectangle).Contains(Cursor.Position) && control.Visible)
{
SendMessage(control.Handle, m.Msg, m.WParam.ToInt32(), m.LParam.ToInt32());
}
}
}
}
This question already has answers here:
Disabling the Close-Button temporarily
(7 answers)
Closed 6 years ago.
How can I disable the close button of a form like in the image below? (the image below show a MessageBox window)
The MessageBox above was generated by me! I want to disable the close button of a normal form.
Right click on the window in question, then click Properties. Under Properties click Events. Double click on the FormClosing event.
The following code will be generated by Windows Form Designer:
private void myWindow_FormClosing(object sender, FormClosingEventArgs e)
{
}
Simply update the code to look like this (add e.Cancel = true;):
private void myWindow_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
You're done!
Alternatively, if you want to disable the close, maximize, and minimize buttons of the window:
You can right click the window in question, then click Properties. Under Properties set the ControlBox property to false.
If you are working with an MDI child window and disabling the close button during creation of the window is ruled out (i.e. you want to disable it at certain times during the form's life) none of the previously proposed solutions will work¹.
Instead we must use the following code:
[DllImport("user32")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32")]
public static extern bool EnableMenuItem(IntPtr hMenu, uint itemId, uint uEnable);
public static void DisableCloseButton(this Form form)
{
// The 1 parameter means to gray out. 0xF060 is SC_CLOSE.
EnableMenuItem(GetSystemMenu(form.Handle, false), 0xF060, 1);
}
public static void EnableCloseButton(this Form form)
{
// The zero parameter means to enable. 0xF060 is SC_CLOSE.
EnableMenuItem(GetSystemMenu(form.Handle, false), 0xF060, 0);
}
¹ You can set ControlBox = false if you do not want any buttons, but that is not what the question is asking.
You handle the Closing event (and not the Closed event) of the Form.
And then you use e.CloseReason to decide if you really want to block it (UserClose) or not (TaskManager Close).
Also, there is small example Disabling Close Button on Forms on codeproject.
You should override the CreateParams function derived from System.Windows.Forms.Form
And change the Class Style
myCp.ClassStyle = 0x200;
Closing += (s, eventArgs) =>
{
DialogResult = DialogResult.None; //means that dialog would continue running
};
I made a custom window for my app and I wrote some code if a user clicks my custom maximize button:
private void MaxThis(object sender, System.Windows.RoutedEventArgs e)
{ if (WindowState == WindowState.Maximized){
WindowState = WindowState.Normal;}
else {
this.Top = 0;
this.Left = 0;
this.MaxWidth = System.Windows.SystemParameters.WorkArea.Width;
this.MaxHeight = System.Windows.SystemParameters.WorkArea.Height;
this.WindowState = WindowState.Maximized;
}
}
The restoring to the normal state works fine. However when I want to maximize, it maximizes the window with a small margin on the right and bottom of the screen. Clicking maximize again fixes this somehow. How do I fix this to maximize at the first click...?
Take away the Height and Width properties you have set in XAML for your window
Try to use just
this.WindowState = WindowState.Maximized;
Perhaps code, goes before messing Windows API action.
Sorry, my mistake.
Then you should use Windows API to raise Maximize event.
Try this code:
[DllImport("user32.dll")]
public static extern int SendMessage(
int hWnd, // handle to destination window
uint Msg, // message
long wParam, // first message parameter
long lParam // second message parameter
);
public const int WM_SIZE = 0x0005;
public const int SIZE_MAXIMIZED = 2;
And in your click event:
SendMessage(this.Handle, WM_SIZE, SIZE_MAXIMIZED, 0);