We have an MDI form which contains some number of child forms which have varying captions showing the currently loaded document's filename. When the child forms are maximized their title text gets placed in the parent window's title bar which often results in the text being too long to fit in the bar and Windows is nice enough to add ellipses and truncate the text.
However, when you hover over the title bar of the main window, it shows a tooltip with what should be the entire string, but instead the tooltip often contains a small fraction of the string. For example, if the main form's text was:
Program1 - Filename:[Really_long_filename_that_doesnt_fit.file]
It would appear as the following in the tooltip:
Program1 - Filename:[Really_long_filename_t
Edit: It always truncates the tooltip at exactly 100 characters, which leads me to believe that it's some upper limit specified somewhere.
Is there a way to change this so it displays the entire string, or if not, to disable the tooltip altogether?
Any language is acceptable, although we're doing this in C#.
This uses a manual tooltip and timer to show / hide a caption when the mouse moves over the title bar.
public partial class Form1 : Form
{
private ToolTip toolTip = new ToolTip();
private Timer toolTipTimer = new Timer();
private bool canShowToolTip = true;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 0x2A0: // WM_NCMOUSEHOVER
return;
case (int)0x00A0: // WM_NCMOUSEMOVE
if (m.WParam == new IntPtr(0x0002)) // HT_CAPTION
{
if (canShowToolTip)
{
canShowToolTip = false;
toolTip.Show(this.Text, this, this.PointToClient(Cursor.Position), toolTip.AutoPopDelay);
toolTipTimer.Start();
}
}
return;
}
base.WndProc(ref m);
}
public Form1()
{
InitializeComponent();
Form child = new Form();
child.Text = "Program1 - Filename:[Really_long_filename_that_doesnt_fit.file] AAAAAAAAAAAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB";
child.MdiParent = this;
child.Show();
toolTip.AutoPopDelay = 5000;
toolTipTimer.Interval = toolTip.AutoPopDelay;
toolTipTimer.Tick += delegate(object sender, EventArgs e)
{
canShowToolTip = true;
};
}
}
I wish I had something more helpful for you, but unfortunately, I don't think that there's a way around this. You may either shorten your filenames or have to deal with it :(
Related
Question:
How do I display a MDI child form in a ShowDialog() format?
What I've tried:
private void Add()
{
ModuleAddPopUp map = new ModuleAddPopUp();
map.StartPosition = FormStartPosition.CenterScreen;
map.ShowDialog();
}
Doing the above, the form displays center screen as a pop-up, however I can drag the form outside the MDI when the MDI isn't maximized.
private void Add()
{
ModuleAddPopUp map = new ModuleAddPopUp();
FormFunctions.OpenMdiDataForm(App.Program.GetMainMdiParent(), map);
}
Doing the above, the form displays center screen, doesn't allow for the form to be dragged outside the MDI, but acts as a map.Show() , rather than a map.ShowDialog();
Add this code to your ModuleAddPopup class:
protected override void WndProc(ref Message message)
{
const int WM_SYSCOMMAND = 0x0112;
const int SC_MOVE = 0xF010;
//SC_SIZE = 0XF000 if you also want to prevent them from resizing the form.
//Add it to the 'if' condition.
switch (message.Msg)
{
case WM_SYSCOMMAND:
int command = message.WParam.ToInt32() & 0xfff0;
if (command == SC_MOVE)
return;
break;
}
base.WndProc(ref message);
}
This is native code wrapped in C# code, as seen in here.
This, however, will prevent the user from moving the dialog form anywhere.
Then, in your main form:
private void Add()
{
ModuleAddPopUp map = new ModuleAddPopUp();
map.StartPosition = FormStartPosition.CenterParent;
map.ShowDialog();
}
I'm working on a Windows Forms app and I'm wanting to remove the close button from the top. I'm aware of the ControlBox option, but I'm wanting to provide a help button. Is there a way to have the Close button not visible while maintaining the help button?
Your best bet may be to subcribe to the FormClosing event of the form like so and cancel the closing action:
// In your code somewhere subscribe to this event
Form1.FormClosing += Form1_FormClosing;
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
The benefit of doing this is that it prevents the user from closing the application from the close button and the taskbar.
Obviously you don't want to ALWAYS cancel the form from closing. So you will want to set some type of boolean flag that you will check in the event listener as to whether you want the form to be allowed to close or not. Example:
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (BlockClosing)
e.Cancel = true;
}
EDIT: If you don't want to approach the problem that way, and you really do intend to completely remove the close button, then your best bet is to create your own custom title bar. In that case, you set the form's FormBorderStyle property to None. And you then dock your custom title bar to the top of the form. Here is some sample code from one I made a while back:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Spectrum.UI
{
public partial class TitleBar : UserControl
{
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler MinButtonClick;
public event EventHandler MaxButtonClick;
public event EventHandler CloseButtonClick;
#region Properties
[Category("Appearance")]
public string Title
{
get { return TitleLabel.Text; }
set { TitleLabel.Text = value; }
}
[Category("Appearance")]
public bool MinimizeEnabled
{
get
{
return minButton.Visible;
}
set
{
minButton.Visible = value;
}
}
[Category("Appearance")]
public bool MaximizeEnabled
{
get
{
return maxButton.Visible;
}
set
{
maxButton.Visible = value;
}
}
#endregion
public TitleBar()
{
InitializeComponent();
ShowTitleBarImage = false;
}
#region Mouse Events
private void TitleBar_MouseDown(object sender, MouseEventArgs e)
{
this.OnMouseDown(e);
}
private void TitleBar_MouseUp(object sender, MouseEventArgs e)
{
this.OnMouseUp(e);
}
private void TitleBar_MouseMove(object sender, MouseEventArgs e)
{
this.OnMouseMove(e);
}
#endregion
#region Button Click Events
private void minButton_Click(object sender, EventArgs e)
{
if (MinButtonClick != null)
this.MinButtonClick.Invoke(this, e);
}
private void maxButton_Click(object sender, EventArgs e)
{
if (MaxButtonClick != null)
this.MaxButtonClick.Invoke(this, e);
}
private void closeButton_Click(object sender, EventArgs e)
{
if (CloseButtonClick != null)
this.CloseButtonClick.Invoke(this, e);
}
#endregion
}
}
As you can see from the image, I also added a background image to the control. Depending on your patience and your requirements, you can use images and PictureBox controls to make this look as much like a standard title bar as you need.
In the above example I placed three buttons on the control with images I found online to represent minimize, maximize, and close. in your case you would simply exclude a close button. I also placed a string on the control with an appropriate font to serve as the title of the window.
Adding the custom title bar to your form is easy.
public TitleBar titleBar = new TitleBar();
titleBar.Dock = DockStyle.Top;
titleBar.MaximizeEnabled = true;
titleBar.MinimizeEnabled = true;
titleBar.Size = new System.Drawing.Size(10, 40); // Width doesn't matter - I wanted it 40 pixels tall
titleBar.Title = "Title Example";
titleBar.MinButtonClick += titleBar_MinButtonClick;
titleBar.Max ButtonClick += titleBar_MaxButtonClick;
this.Controls.Add(this.TitleBar);
And then last step is to set up your event listeners for the min and max button clicks:
private void titleBar_MinButtonClick(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private void titleBar_MaxButtonClick(object sender, EventArgs e)
{
WindowState = FormWindowState.Maximized;
}
You may also note that I included events for mouse down, up and move in my title bar. This was so that I could create listeners in my form to move the form when the user clicked and dragged the title bar. This is optional and depends on if you need the user to be able to move your application window.
The added benefit of doing this is that can use the title bar for additional controls. For example, my application was custom written for use on a toughbook style tablet computer with a small touchscreen display. In my application, utilization of the limited space was extremely important. I was able to further modify what I've described here to also include menu bar style control directly on the title bar. In addition, I added more buttons to the left of the stand minimize, maximize, and close buttons. Really helped me utilize every square inch of the screen in my application. Couldn't have done it with the standard title bar.
Can you simply use Form.ControlBox = false (or via the designer as you point out rather negatively in your comment) and then add a custom help button on the form?
EDIT: A colleague of mine wrote an Excel add in and had a requirement to remove the X from certain forms (e.g. a Progress Bar that shouldn't be closed). He found a function written by Stephen Bullen that did just that. I've only seen this function used in VB, but perhaps you can get some ideas or direction out of his approach of using Windows API to solve your issue.
This code will disable the Close button. I am not sure if you can actually make it invisible. http://www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms
//
// source code
// Code Snippet
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams myCp = base.CreateParams;
myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON ;
return myCp;
}
}
Good luck!
Please try this.ControlBox = false.
I just don't know how to explain my problem. So I have created an image.
(I am not using WPF)
So now I have problem connected with my old problem.
Now I have the new "cool" border around my form.
But it is working only when I use FormBorderStyle.SizableToolWindow or FormBorderStyle.Sizable otherwise it is "borderless".
But I wanna have non-resizable form...
My poor solution:
I can use maximumsize = this.size; and minimumsize = this.size but when I put my cursor over the border then my cursor changes to "resize" cursor... and that is ugly...
I hope you will understand me.
Thanks
You need to set your form to have no title and also to, as you say, hide the control box. You can change both of these in the Properties panel for your form.
Or, in code:
public Form1()
{
InitializeComponent();
ControlBox = false;
Text = "";
}
Note that this will cause your form to be undraggable (if it's not already resizable), and you need to add your own control to handle closing the form.
EDIT: one way to prevent the window from being resizable and prevent the cursor from changing to the resize handles is to override the WndProc() handler for the form and intercept WM_NCHITTEST.
Place this method in your form class, and keep the FormBorderStyle as FormBorderStyle.Sizable or FormBorderStyle.SizableToolWindow:
protected override void WndProc(ref Message message)
{
const int WM_NCHITTEST = 0x0084;
if (message.Msg == WM_NCHITTEST)
{
return;
}
base.WndProc(ref message);
}
Basically I am having two problems with C#.NET MDI. You can download VS2010 solution which reproduces bugs here.
1) When programmatically hiding and showing again a maximized child form, it is not maximized properly again and becomes neither maximized or in normal state.
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
...
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
}
...
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
}
When child form is maximized, then programicaly hidden and shown again, it becomes something like this (please notice the menu bar - child form's control box appears, but child form is not maximized):
At this stage, child form cannot be moved around. However, I found a workaround for that, simply by showing and hiding a dummy child form, which forces the actual child form to become properly maximized. But this makes MDI area to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Maybe there are other workarounds to overcome this bug and not to make MDI area flicker with dummy child form?
private void workaround1Button_Click(object sender, EventArgs e)
{
dummyForm.Visible = true;
dummyForm.Visible = false;
}
2) When child form is maximized, the icon of the child form is displayed on menu bar. However, if you have to change the icon while the child form is maximized, the icon on the menu bar is not being refreshed (see the image above). I found a workaround for that too, which basically hides and shows menu bar. Icon gets refreshed, but it makes everything below menu bar to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Is there any other way to make menu bar to refresh the child form's icon?
private void workaround2Button_Click(object sender, EventArgs e)
{
menuStrip.Visible = false;
menuStrip.Visible = true;
}
Also I noticed that when parent form is in normal window state mode (not maximized) and you change the width or height of the form by 1 pixel, child form becomes maximized as it should be and child form's icon on menu bar gets refreshed properly and you don't need other workaround I described above. If I change the size of the form programicaly, form flickers by 1 pixel and I cannot do that, when parent form is maximized. Is there any way how I could invoke the repaint/refresh functionality which is called when you resize a form and which makes child form become maximized properly and the icon on the menu bar refreshed?
There's a bug in the implementation of the internal MdiControlStrip class, the control that displays the icon and the min/max/restore glyphs in the parent window. I haven't characterized it as yet, the code isn't that easy. A classic side effect of the bug is that the glyphs get doubled up, you found some other side-effects. The fix is simple though, delay creating the child windows until after the constructor is completed. Like this:
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e) {
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
dummyForm = new Form();
dummyForm.MdiParent = this;
dummyForm.WindowState = FormWindowState.Maximized;
base.OnLoad(e);
}
Have you tired using Hide/Show instead of setting visible to true/false?
Try:
private void showButton_Click(object sender, EventArgs e)
{
childForm.Show();
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Hide();
}
How about this workaround?
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
childForm.WindowState = (FormWindowState)childForm.Tag;
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
childForm.Tag = childForm.WindowState;
childForm.WindowState = FormWindowState.Normal;
}
UPDATE
I just gave you the idea how you could do. A better solution using the same idea as above would be a new base form which saves the windows state. See below. Derive your forms from FixedForm instead of Form:
public partial class FixedForm : Form
{
private FormWindowState lastWindowState;
public FixedForm()
{
InitializeComponent();
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
WindowState = lastWindowState;
}
else
{
lastWindowState = WindowState;
WindowState = FormWindowState.Normal;
}
}
}
Found a way how to come around those bugs.
First of all you need to suspend painting for a form and its children. I found a very helpful thread here, which describes how to do it.
After suspending painting, you need call UpdateBounds method of the control and increase ClientRectangle Width or Height by one and then decrease it back to the same value it was before. This invokes layout functionality which makes everything to update/repaint. Last step is to enable painting. Not very nice solution I guess, but it works.
StopDrawing();
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height + 1);
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height - 1);
StartDrawing();
I find suspending painting very helpful not only for working around those two bugs, but also in general to make GUI work more smoothly. I guess this can help to remove any kind of flickering. However, this solution requires P/Invokes, which should be avoided in general.
Why not just manually reset required icon in menuStrip items, after the creation of the window:
menuStripMain.Items[0].Image = null;
I have been working with NotifyIcon in order to show an icon in the taskbar.
This program has no Windows Form. I perhaps could create one and make it invisible but I was hoping to avoid it. The ToolTip functions attached to NotifyIcon are somewhat lacking, and one of the gurus here suggested I look at the ToolTip functionality. It is possible to attach ToolTip to a form. Is is possible to attach it to just the NotifyIcon? I'm trying do this:
NotifyIcon CTicon = new NotifyIcon();
ToolTip toolTip = new ToolTip();
toolTip.SetToolTip(CTicon, "Test");
And I get the error "cannot convert from 'System.Windows.Forms.NotifyIcon' to 'System.Windows.Forms.Control'. Is there a way to convert? I also tried:
toolTip.SetToolTip(CTicon.Container, "Test");
but a container is apparently not a valid control either.
I apologize for my total lack of understanding of how this may or may not work.
Thanks in advance.
A belated answer, but maybe useful for others .
NotifyIcon.Text = "ToolTipText";
Tray icons don't support square tool tips, only balloons. Kinda makes sense, the icons are usually quite close together so it would be hard to see what icon produced the tip without the "stem" on the balloon. Use the NotifyIcon.BalloonTipText property.
NotifyIcon is used for the system tray icon that you see on the bottom right hand corner of the screen, usage of ToolTip is only for controls such as textboxes, checkboxes and so on...for example, let's assume there's a TextBox instance called 'textBox1', on the form than this would work:
toolTip1.SetToolTip(textBox1, "Hello World");
Now, when you mouse-over the textbox, a tooltip is shown...
I'm not sure you can set a tooltip directly on a notify icon. It's the same thing as setting the text property on the notify icon itself. There are some limitations to the notify icon text. It's limited to 128 chars and will only stay up for a short amount of time. If you want to display more info for a longer amount of time you should look at the balloon text property of the notify icon. I highly suggest reading the MSDN page it's quite helpful.
http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.aspx
You shouldn't.
NotifyIcon is used to show notifications, whereas ToolTip is used to show the information about the user's current activity, it should be used "in place".
Check the user interface guidelines:
Notifications
Balloons
All the tray icons on my computer have tooltips. You need to create your NotifyIcon using the constructor that accepts a Component as an argument. It displays the NotifyIcon.Text property.
I was able to create one using the example code here:
http://msdn.microsoft.com/en-us/library/1by05f8d.aspx
using System;
using System.Drawing;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.NotifyIcon notifyIcon1;
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.ComponentModel.IContainer components;
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
this.components = new System.ComponentModel.Container();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
// Initialize contextMenu1
this.contextMenu1.MenuItems.AddRange(
new System.Windows.Forms.MenuItem[] {this.menuItem1});
// Initialize menuItem1
this.menuItem1.Index = 0;
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
// Set up how the form should be displayed.
this.ClientSize = new System.Drawing.Size(292, 266);
this.Text = "Notify Icon Example";
// Create the NotifyIcon.
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
// The Icon property sets the icon that will appear
// in the systray for this application.
notifyIcon1.Icon = new Icon("appicon.ico");
// The ContextMenu property sets the menu that will
// appear when the systray icon is right clicked.
notifyIcon1.ContextMenu = this.contextMenu1;
// The Text property sets the text that will be displayed,
// in a tooltip, when the mouse hovers over the systray icon.
notifyIcon1.Text = "Form1 (NotifyIcon example)";
notifyIcon1.Visible = true;
// Handle the DoubleClick event to activate the form.
notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);
}
protected override void Dispose( bool disposing )
{
// Clean up any components being used.
if( disposing )
if (components != null)
components.Dispose();
base.Dispose( disposing );
}
private void notifyIcon1_DoubleClick(object Sender, EventArgs e)
{
// Show the form when the user double clicks on the notify icon.
// Set the WindowState to normal if the form is minimized.
if (this.WindowState == FormWindowState.Minimized)
this.WindowState = FormWindowState.Normal;
// Activate the form.
this.Activate();
}
private void menuItem1_Click(object Sender, EventArgs e) {
// Close the form, which closes the application.
this.Close();
}
}