Using a designed form for tooltip in c# - c#

Currently I am developing a .NET WinForms application in C#.
I want to use a form created in designer as a custom tooltip for my project's controls.
Is there a way to do it?

One could argue whether this question is a duplicate of create custom tooltip C# but as it does not provide an example but just a link I think it's good to list the most important points:
To design your custom ToolTip you need to create a new type derived from ToolTip and handle the Draw event where you draw what you need. Rebuild your project and the CustomToolTip should now appear in the Toolbox.
class CustomToolTip : ToolTip
{
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw += new DrawToolTipEventHandler(this.OnDraw);
}
// Sets the size of the CustomToolTip.
private void OnPopup(object sender, PopupEventArgs e)
{
e.ToolTipSize = new Size(100, 100);
}
// Draws the CustomToolTip.
private void OnDraw(object sender, DrawToolTipEventArgs e)
{
// your drawing...
}
}
If you want to use a form for that you'd have create your own logic for showing it on MouseEnter etc. or use 3rd party libraries.

Related

C# Button.image

I've been on this for a while but can't get it to work.
I came from C# programming within Unity3D, but now need to build something in "normal" C# now through Visual Studio.
So I've got this button in C#, which I want to give a background. No biggy.
But the problem is, I want the background to expand itself.
So I want an image like this: !http://i39.tinypic.com/2wphvo6.png combined with a button so it becomes like this: !http://i42.tinypic.com/dzxlom.jpg
In Unity3D it was easy, but I don't know how to get it to work in Visual Studio C#. Hope someone can help me. I don't even know how to properly call this image expanding to button thing...
edit: Windows Forms
Assuming you want the change the picture on mouse over you can do something like this using events
public Form1()
{
InitializeComponent();
button1.MouseEnter += new EventHandler(button1_MouseEnter);
button1.MouseLeave += new EventHandler(button1_MouseLeave);
}
void button1_MouseLeave(object sender, EventArgs e)
{
this.button1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.img1));
this.button1.Size = button1.BackgroundImage.Size;
}
void button1_MouseEnter(object sender, EventArgs e)
{
this.button1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.img2));
this.button1.Size = button1.BackgroundImage.Size;
}
You need to set the BackgroundImageLayout property.
public Form1()
{
InitializeComponent();
button1.BackgroundImageLayout = ImageLayout.Stretch; //Or maybe you want Zoom
}
You can also set the property in the design view of the form.

Winforms Control

I have a button which I use all the time as a little pick button next to a combobox. When I click the button I open a larger full list. This side of things work well and I do not have a problem with this..
My problem lies when someone said to me can you change that ugly icon you picked to my nice icon.
I went crap, I have hundreds of these buttons on many forms. So I thought I will create a custom control called PickButton (which is a standard button and heap of default proeprties set) and drop these on the form everywhere instead. In the code of the PickButton custom control I set some properties and the image to the customers nice icon.
So I drop the PickButton from my toolbox onto the form, so far things are looking pretty good and I am feeling a bit clever. Now I think to myself I will change back to my nice icon not the crappy one the customer picked and change the code in the PickButton custom control. But I cannot get rid of that customers icon, because the code when the PickButton run happens before the code in the designer file which has the customers icon.
So my aim was to have a PickButton control and be able to change the icon and other properties in one place and all the properties would be set when an instance of the control is created and displayed on the form.
Was I not so clever and went about achieving the task the wrong way???
This is my PickButton custom control class
public class PickButton : Button
{
public PickButton()
{
InitialiseButton();
}
internal void InitialiseButton()
{
this.ImageAlign = ContentAlignment.MiddleCenter;
this.Image = WindowsFormsApplication1.Properties.Resources.Cancel.ToBitmap();
this.Size = new Size( 28, 28 );
this.Dock = DockStyle.Fill;
this.Margin = new Padding( 0, 2, 2, 0 );
this.Text = string.Empty;
}
}
Now I drop one onto my form and the code in the designer is as follows
//
// pickButton1
//
this.pickButton1.Dock = System.Windows.Forms.DockStyle.Fill;
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
this.pickButton1.Location = new System.Drawing.Point(0, 0);
this.pickButton1.Margin = new System.Windows.Forms.Padding(0, 2, 2, 0);
this.pickButton1.Name = "pickButton1";
this.pickButton1.Size = new System.Drawing.Size(284, 262);
this.pickButton1.TabIndex = 0;
this.pickButton1.Text = "pickButton1";
this.pickButton1.UseVisualStyleBackColor = true;
Now I want to change the image so I change my PickButton code to use a different icon
this.Image = WindowsFormsApplication1.Properties.Resources.Browse.ToBitmap();
Run the application andd the first icon is still the one being displayed because of this line of code in the designer file
this.pickButton1.Image = ((System.Drawing.Image)(resources.GetObject("pickButton1.Image")));
The concept of setting all the properties in one place was a good idea, it just wasn't implemented quite right. I would make this class inherit from UserControl instead of from Button. By making it a UserControl, you can use the designer to set all the properties you want, like the default Image for the button. Set that in the designer, then just drag and drop your UserControl from the toolbox onto your forms. If you are only using your "PickButton" control with comboboxes, I would put the combobox on the UserControl as well. If you ever want to change your button image in the future (or any other property for that matter), you will be able to change it in ctlPickButton and that will propogate the changes to all the instances used throughout your project(s).
ctlPickButton:
public partial class ctlPickButton : UserControl
{
public event EventHandler pickButtonClicked;
public ctlPickButton()
{
InitializeComponent();
}
//Allows buttons image to be set in code if necessary
public Image Image
{
get
{
return button1.Image;
}
set
{
if (Image != null)
{
button1.Image = value;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
if (pickButtonClicked != null)
{
pickButtonClicked(sender, e);
}
}
}
Demo Form:
public Form1()
{
InitializeComponent();
ctlPickButton1.pickButtonClicked += new EventHandler(ctlPickButton1_pickButtonClicked);
ctlPickButton2.pickButtonClicked += new EventHandler(ctlPickButton2_pickButtonClicked);
}
void ctlPickButton2_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox2.SelectedItem != null)
{
MessageBox.Show(comboBox2.SelectedItem.ToString());
}
}
void ctlPickButton1_pickButtonClicked(object sender, EventArgs e)
{
if (comboBox1.SelectedItem != null)
{
MessageBox.Show(comboBox1.SelectedItem.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.Add("French");
comboBox1.Items.Add("Spanish");
comboBox1.Items.Add("English");
comboBox1.Items.Add("German");
comboBox2.Items.Add("Pizza");
comboBox2.Items.Add("Hamburger");
comboBox2.Items.Add("Potato");
comboBox2.Items.Add("Chicken");
//Shows how the default image set in the designer can be overwritten for a
//specific instance using the "Image" property
ctlPickButton2.Image = Testbed.Properties.Resources.searchIcon2;
}
}
Image of ctlPickButton in designer
I think I've found a simple, clean solution:
In the CustomButton class (which inherits from System.Windows.Forms.Button), override the Refresh() method, and set the image of the button to the one you want to see:
public class CustomButton : Button
{
public override void Refresh()
{
Image = MyResources.HappyFace;
}
}
In the form that will hold an instance of your CustomButton, simply call customButton.Refresh() in the constructor, after InitializeComponent():
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
customButton.Refresh();
}
}
I've put a demo application up on Github.

Is there a property in Label that allows font resizing with class?

I notice all the other controls I am using such as tabs, textboxes, rich textboxes with text already inside it and everything else resize automatically when I change the main Form font. But labels are an exception to this rule is there a property I can turn on or off in the Label that will make it resize font with the form? It is a pretty straightforward yes or no question I know how to work around it I just like how all my controls are automatically resizing without any unnecessary code.
I've a solution here:
If your controls have the same font with your Form's Font, you shouldn't change the particular Font of them (via the Properties window or via code), instead you just change your Form's Font. If that has already been done, you can find the code lines (normally in Form.Designer.cs) which specify Font for your controls (something like yourControl.Font = ...) and remove those lines.
If your controls need different Font from your Form's. You can register the FontChanged event handler of your Form and change its children controls' Fonts accordingly (just the font size):
private void Form1_FontChanged(object sender, EventArgs e){
UpdateChildrenFont(this);
}
private void UpdateChildrenFont(Control parent){
foreach(Control c in parent.Controls){
c.Font = new Font(c.Font.FontFamily, parent.Font.Size, c.Font.Style);
UpdateChildrenFont(c);
}
}
The recursive method UpdateChildrenFont works in most cases but if you have some TabControl on your form, that doesn't work, because TabControl has another kind of collection to hold its tab pages called TabPages... I've encountered such a case. Another solution is to create your own Controls and override the OnParentChanged to register the Parent.FontChanged event handler accordingly, like this:
public class YourControl : TheBaseControl {
protected override void OnParentChanged(EventArgs e){
if(Parent != null){
Parent.FontChanged -= ParentFontChanged;
Parent.FontChanged += ParentFontChanged;
}
}
private void ParentFontChanged(object sender, EventArgs e){
Font = new Font(Font.FontFamily, Parent.Font.Size, Font.Style);
}
}
You should apply that model on all your controls on your form. That's very clean although requires you to have custom classes for your controls.
The last solution I can think of is playing with ControllAdded event, this is applied only on your Containers such as Form, GroupBox, Panel... and every control which has some child control on your form. Here is the code:
public class YourContainerClass: YourContainerBaseClass {
protected override void OnControlAdded(ControlEventArgs e){
Binding bind = new Binding("Font", this, "Font");
bind.Format += (s, ev) =>
{
Font inFont = (Font)ev.Value;
Binding bin = (Binding)s;
ev.Value = new Font(bin.Control.Font.FontFamily, inFont.Size, bin.Control.Font.Style);
};
e.Control.DataBindings.Clear();
e.Control.DataBindings.Add(bind);
base.OnControlAdded(e);
}
}
Or simply if that's your Form:
public class Form1 : Form {
public Form1(){
ControlAdded += FormControlAdded;
InitializeComponent();
}
private void FormControlAdded(object sender, ControlEventArgs e){
Binding bind = new Binding("Font", this, "Font");
bind.Format += (s, ev) =>
{
Font inFont = (Font)ev.Value;
Binding bin = (Binding)s;
ev.Value = new Font(bin.Control.Font.FontFamily, inFont.Size, bin.Control.Font.Style);
};
e.Control.DataBindings.Clear();
e.Control.DataBindings.Add(bind);
}
}

Is there a way to set a control as a tooltip?

I'm wondering if it's possible to use ToolTip.SetToolTip or something similar to open a control as a tooltip instead of just a string (i.e. SetToolTip(controlToWhichToAdd, panelToDisplayAsToolTip) instead of passing a string as your second parameter).
If this isn't possible I'm guessing next best thing is displaying a panel on the mouse location on mouse_enter event on the control and removing it (or making it invisible) on mouse_leave.
Or are there other practices that make this possible in an easier way?
This is not possible out of the box. You have two choices. First option is to override the Draw Event, which will let you customize how the tooltip looks. Here is an example of this. Be sure you set the OwnerDraw property to true if you use this method!
Although the first method will work if you just need some simple customization, the second option will work best if you need more flexible options. The second option is to do what you already suggested and create your own sort of tooltip. Simply put, you would first create an event handler for the MouseEnter event. When that event fires, you'd enable a Timer. This timer would be the delay that occurs before the tooltip is show. Then finally, you'd just make your panel appear at the mouse coordinates.
Suppose you have a form with a button and timer on it and you want the button to have a tooltip that is a panel:
public partial class Form1 : Form
{
private Panel _myToolTipPanel;
private void Form1_Load(object sender, EventArgs e)
{
_myToolTipPanel = new Panel {Visible = false};
Controls.Add(_myToolTipPanel);
Label myLabel = new Label();
myLabel.Text = "Testing";
_myToolTipPanel.Controls.Add(myLabel);
}
private void button1_MouseEnter(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void button1_MouseLeave(object sender, EventArgs e)
{
timer1.Enabled = false;
_myToolTipPanel.Visible = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
Point position = Cursor.Position;
Point formPoisition = PointToClient(position);
_myToolTipPanel.Visible = true;
_myToolTipPanel.Location = formPoisition;
}
}
Now of course you will have to do some beautifying of the tooltip, but this is the general idea!
One Approach could be inheriting the ToolTip control and then override the SetToolTip and Show methods . Inside the SetToolTip the private method - SetToolTipInternal needs to be re-written , but most of the functionality could be reuse - it uses the Mouse Events ( leave , move) to bind region. but since tooltip uses internal's of windows to show the baloon window. you will have to override quite a bit of code.
but this could be time consuming and needs quite a bit of testing.
You could write a handler for the Tooltip.Popup event, and cancel the popup to display your own panel.
You'd need to clean it up at the appropriate time, though.
For example:
private void ToolTip1_Popup(Object sender, PopupEventArgs e)
{
e.Cancel = true;
//Do work here to display whatever control you'd like
}
If you're just looking for more formatting options in the tooltip display, an alternative is something like this CodeProject entry, which implements an HTML-enabled tooltip:

How do I create a custom C# control that has some common functionality?

I am very new to C# programming. I come from autoit, and other scripting languages, the transition has been most difficult. Anyway I am working on a control in a windows form, basically I want it to be a LinkLabel control, that when you click it, it will become a textbox, once you enter your name, and either hit enter, or tab, it will set your name as the linklabel. But, I will have 10 of these controls on a form, and the way I have done it, it has taken three methods per control, so that is a lot of code, I'm sure I'm just doing it wrong, but here is what i have:
namespace Program
{
public partial class formMain : Form
{
public formMain()
{
InitializeComponent();
}
private void linkLabelPlayerName1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
this.linkLabelPlayerName1.Hide();
this.textBoxPlayerName1.Show();
this.textBoxPlayerName1.Focus();
this.textBoxPlayerName1.KeyPress += new KeyPressEventHandler(textBoxPlayerName1_KeyPress);
this.textBoxPlayerName1.LostFocus += new EventHandler(textBoxPlayerName1_LostFocus);
}
private void textBoxPlayerName1_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
this.linkLabelPlayerName1.Text = this.textBoxPlayerName1.Text;
this.textBoxPlayerName1.Hide();
this.linkLabelPlayerName1.Show();
}
}
private void textBoxPlayerName1_LostFocus(object sender, EventArgs e)
{
this.linkLabelPlayerName1.Text = this.textBoxPlayerName1.Text;
this.textBoxPlayerName1.Hide();
this.linkLabelPlayerName1.Show();
}
}
}
I'm sure there is a way to use the last two methods between all 10 controls, so they don't have to be rewritten for each control. That is, textBoxPlayerName1_LostFocus() and textBoxPlayerName2_LostFocus().
Welcome to object orientated programming :).
You should created a derived class to encapsulate the functionality. For example:
class EditableText : UserControl
{
private LinkLabel lblName;
private TextBox txtName;
public EditableText()
{
// Construct objects, attach events and add them
// as children to this object
}
// Return the text of encapsulated TextBox
public string Text
{
get { return txtName.Text; }
}
}
Now you are able re-use this class in different areas, that's what object orientated programing all about!
Right-click on the windows forms application in the Solution Exporer, and select Add, then User Control...
Type in a name for the new control, like LinkLabelTextBox
This will give you a space to work in that looks like a Form, but without borders. This is your new control. Put your LinkLable and TextBox on this new control exactly as you put them in the window, and give them the functionality that you want. Then replace all your existing controls with instances of this new control. You will create 10 of these, instead of creating ten LinkLabels and ten TextBoxes. And all of the functionality that you want will be built-in to your new control, so that code does not need to be repeated.
Instead of a linkLabelPlayerName1 and textBoxPlayerName1, you will have a linkLabelTextBoxPlayerName1, and none of the Show, Hide, Focus stuff will clutter your form code.
Also, be sure to include a public Text property so you can get the value that the user typed out of this control.
Create your own Control with the functionality.
Your code is correct.
To make it cleaner, you should move it to a separate UserControl, and set the Text property to the textbox's value.

Categories

Resources