I wonder if it's possible to customize my C# application (winforms) to get a better design, I made a PSD (photoshop document) so I can generate png jpeg... pictures if I need them.
Example of a form like the one I want :
Indeed as it was pointed out in the comments, it is easy to use WPF (indows Presentation Foundation) to achieve that result, but if you really need that it must be made in windows forms I can help you with that...
ControlBox and Border
It seens that your form does not have a control box (minimize, maximize and close buttons)
to achieve that you can set
form.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
I'm not sure if that galaxy behind your form is part of the application so i'll be considering that it is not
To achieve that irregular shape of the form we have to do a workaround here
Irregular Shape of the Form
we are going to set a Color to TransparentKey, so everything in the form in that specific color will be transparent, like it does not exists (if you click in that part it will go into de desktop or whatever application you have behind in your form)
So let's use a specific color which we will probably dont use in the form
form.TransparencyKey = Color.FromArgb(111, 111, 111); //You can do it by the editor
So in order to make that white part we are going to use an Panel and a PictureBox outsite of the Panel trying to copy the shape of your image
Stylized Inputs
To make it easier and reusable I'm going to make a userControl in this one
the usercontrol will have
a Panel called HighLightPanel, its dock property will be set to Fill
a Panel called BackColorPanel, it will be inside the HighLightPanel
a PictureBox called InputPicture, its dock property will be set to Left, it will be inside BackColorPanel and its acessor will be public
a TextBox called TextBox, its dock property wil be set to fill, it will be inside BackColorPanel, the BorderStyle Property set to None, you should set the size and font you most desize in this one, I'm going to use Segoe UI; 15,75pt and its acessor will be public
Now we have to make some properties in our UserControl to make it work without work in other controls
First in the SizeChanged event of the HighLightPanel we will make the BackColorPanel be exacly two points smaller in every direction and its position to 1;1 so we can see the HighLightPanel
private void HighlightPanel_SizeChanged(object sender, EventArgs e)
{
this.BackColorPanel.Size = new Size(
HighlightPanel.Width - 2,
HighlightPanel.Height - 2);
}
Now we will create two propertys to handle the Highlight Color
public Color HighlightBorderColor { get; set; }
public Color NonHighlightBorderColor { get; set; }
And in the Enter and Leave Property of our TextBox we are going to change the HighlightPanel
private void TextBox_Enter(object sender, EventArgs e)
{
HighlightPanel.BackColor = HighlightBorderColor;
}
private void TextBox_Leave(object sender, EventArgs e)
{
HighlightPanel.BackColor = NonHighlightBorderColor;
}
So now every time the user enter the Input it will appear that the Input has an Border in the specified Color
Now to enhance its usability to developers we will make some wrappers in its controls to be easier change property of child controls in the editor
public Image InputImage
{
get { return InputPicture.Image; }
set { InputPicture.Image = value; }
}
public PictureBoxSizeMode InputImageLayout
{
get { return InputPicture.SizeMode; }
set { InputPicture.SizeMode = value; }
}
public char PasswordCharacter
{
get { return TextBox.PasswordChar; }
set { TextBox.PasswordChar = value; }
}
public bool ShowInputImage
{
get { return InputPicture.Visible; }
set { InputPicture.Visible = value; }
}
In the InputImage set the picture you want for the User and the Key
Insert the two controls in the position you like
Position of the Form
if you want your form to be moveable without the border you will have to use this snippet, it is more easy in WPF
#region MoveForm
Point LastPoint;
bool ShouldMove;
private void form_MouseDown(object sender, MouseEventArgs e)
{
LastPoint = e.Location;
ShouldMove = true;
this.TransparencyKey = Color.FromArgb(111, 111, 111);
}
private void form_MouseUp(object sender, MouseEventArgs e)
{
ShouldMove = false;
}
private void form_MouseMove(object sender, MouseEventArgs e)
{
if (ShouldMove)
{
this.Location = new Point(
this.Location.X - LastPoint.X + e.X,
this.Location.Y - LastPoint.Y + e.Y);
}
}
#endregion
If you need a lot of special graphics effects learning WPF will indeed be a sound investement.
If all you want is that login screen, it is trivial in Winforms and doesn't take any horrible hacks as you've been told..
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.BackColor = System.Drawing.Color.LavenderBlush;
this.TransparencyKey = System.Drawing.Color.LavenderBlush;
this.ControlBox = false;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Text= "";
These seven lines are all it takes for a form to be transparent. I copied them from the Designer code; you can simply set the 7 Properties in the property grid.
Now add a panel, dock it to the bottom and give it the right color; add a picturebox and your other controls and you are set.
To create the two input groups you also need just a few regular controls and only a few simple lines of code:
You place one Panel, BorderStyle = FixedSingle; and add a Label and a TextBox to it. The Label has AutoSize = False; and both ImageAlign and TextAlign are set to MiddleLeft. You assign an image to the Label's Image and prefix the Text with enough blanks to not overlap. Obviously you should define a PasswordChar for the 2nd TextBox. Now all you need is to script the Enter and Leave events to change the BackColor of the respective Panels between, say SystemColors.Control and SystemColors.MenuHighlight. Size the Labels to almost fill the Panels and you are done. Less code than the WPF version, I'd bet.
If you need such input an controls again and again, simply create Usercontrols for each type you need!
Here is an example of the limits you will hit: Wouldn't it be nice to add a dropshadow effect to the image? It is doable in Winforms. But it would involve painting that effect; this would take at least 15 or 20 lines of involved code instead of simply turning the effect on with (estimated) 1-3 simple lines.
Do you need any nice hover effects? Not easy, to say the least..
These limits will be all over the place, so it really depends on how fancy your requirements will get.
Maybe you should use this example as a starter to compare the two techniques and to warm you up to WPF?
Related
I have a panel1 with AutoScroll = true.I have to make panel1 scroll with btnUp and btnDown. So far I've made what I was asked for
private void btnUpClicked(Object sender, EventArgs e)
{
if (panel1.VerticalScroll.Value - 55 > 0)
panel1.VerticalScroll.Value -= 55;
else panel1.VerticalScroll.Value = 0;
}
private void btnDownClicked(Object sender, EventArgs e)
{
panel1.VerticalScroll.Value += 55;
}
But now I need to hide Scrollbar or make it invisible. I tried
panel1.VerticalScroll.Visible = false;
but it doesn't work. Any ideas guys?
Ok, I've done the working example of this for you. All you have to do is to change the max value depending on the total size of all the items inside your panel.
Form code:
public partial class Form1 : Form
{
private int location = 0;
public Form1()
{
InitializeComponent();
// Set position on top of your panel
pnlPanel.AutoScrollPosition = new Point(0, 0);
// Set maximum position of your panel beyond the point your panel items reach.
// You'll have to change this size depending on the total size of items for your case.
pnlPanel.VerticalScroll.Maximum = 280;
}
private void btnUp_Click(object sender, EventArgs e)
{
if (location - 20 > 0)
{
location -= 20;
pnlPanel.VerticalScroll.Value = location;
}
else
{
// If scroll position is below 0 set the position to 0 (MIN)
location = 0;
pnlPanel.AutoScrollPosition = new Point(0, location);
}
}
private void btnDown_Click(object sender, EventArgs e)
{
if (location + 20 < pnlPanel.VerticalScroll.Maximum)
{
location += 20;
pnlPanel.VerticalScroll.Value = location;
}
else
{
// If scroll position is above 280 set the position to 280 (MAX)
location = pnlPanel.VerticalScroll.Maximum;
pnlPanel.AutoScrollPosition = new Point(0, location);
}
}
}
Picture example:
You have to set AutoScroll option to False on your panel. I hope you understand what I've done and will get your panel running the way you want. Feel free to ask if you have any questions.
The Panel control takes on the duty you gave it by setting AutoScroll to true pretty serious. This always includes displaying the scrollbar gadget if it is necessary. So what you tried cannot work, hiding the vertical scrollbar forces Panel to recalculate layout since doing so altered the client area. It will of course discover that the scrollbar is required and promptly make it visible again.
The code that does this, Panel inherits it from ScrollableControl, is internal and cannot be overridden. This was intentional.
So using AutoScroll isn't going to get you anywhere. As an alternative, do keep in mind what you really want to accomplish. You simply want to move controls up and down. Easy to do, just change their Location property. That in turn is easiest to do if you put the controls on another panel, big enough to contain them. Set its AutoSize property to True. And implement you buttons' Click event handlers by simply changing that panel's Location property:
private const int ScrollIncrement = 10;
private void ScrollUpButton_Click(object sender, EventArgs e) {
int limit = 0;
panel2.Location = new Point(0,
Math.Min(limit, panel2.Location.Y + ScrollIncrement));
}
private void ScrollDownButton_Click(object sender, EventArgs e) {
int limit = panel1.ClientSize.Height - panel2.Height;
panel2.Location = new Point(0,
Math.Max(limit, panel2.Location.Y - ScrollIncrement));
}
Where panel1 is the outer panel and panel2 is the inner one that contains the controls. Be careful when you use the designer to put controls on it, it has a knack for giving them the wrong Parent. Be sure to use the View + Other Windows + Document Layout helper window so you can see this going wrong. After you filled it, set its AutoSizeMode property to GrowAndShrink so it snaps to its minimum size.
Try this:
panel.AutoScroll = true;
panel.VerticalScroll.Enabled = false;
panel.VerticalScroll.Visible = false;
Edit:
Actually when AutoScroll = true; It will take care of hscroll and vscroll automatically and you wont be able to change it. I found this on Panel.AutoScroll Property on MSDN
AutoScroll maintains the visibility of the scrollbars automatically. Therefore, setting the HScroll or VScroll property to true has no effect when AutoScroll is enabled.
You may try this to workaround this problem, I have copied it from this Link.
Behavior Observations 1:
If AutoScroll is set to true, you can't modify anything in VerticalScroll or HorizontalScroll. AutoScroll means AutoScroll; the control decides when scrollbars are visible, what the min/max is, etc. and you can't change a thing.
So if you want to customize the scrolling (e.g. hide scrollbars), you must set AutoScroll to false.
Looking at the source code for the ScrollableControl with Lutz Roeder's .NET Reflecter, you can see that if AutoScroll is set to true, it ignores your attempts to change property values within the VerticalScroll or HorizontalScroll properties such as MinValue, MaxValue, Visible etc.
Behavior Observations 2:
With AutoScroll set to false, you can change VerticalScroll.Minimum, VerticalScroll.Maximum, VerticalScroll.Visible values.
However, you cannot change VerticalScroll.Value!!! Wtf! If you set it to a non-zero value, it resets itself to zero.
Instead, you must set AutoScrollPosition = new Point( 0, desired_vertical_scroll_value );
And finally, SURPRISE, when you assign positive values, it flips them to negative values, so if you check AutoScrollPosition.X, it will be negative! Assign it positive, it comes back negative.
So yeah, if you want custom scrolling, set AutoScroll to false. Then set the VerticalScroll and HorizontalScroll properties (except Value). Then to change the scroll value, you need to set AutoScrollPosition, even though you aren't using auto scrolling! Finally, when you set the AutoScrollPosition, it will take on the opposite (i.e. negative) value that you assign to it, so if you want to retrieve the current AutoScrollPosition later, for example if you want to offset the scroll value by dragging the mouse to pan, then you need to remember to negate the value returned by AutoScrollPosition before reassigning it to AutoScrollPosition with some offset. WOW. Wtf.
One other thing, if you are trying to pan with the mouse, use the values of Cursor.Position rather than any mouse locations returned by the mouse events parameters. Scrolling the control will cause the event parameter values to be offset as well, which will cause it to start firing mouse move events complete with undesired values. Just use Cursor.Position, because it will use mouse screen coordinates as a fixed frame of reference, which is what you want when you're trying to pan/offset the scroll value.
I have design 1 winform to look like the picture. But I want the highlighted yellow part to be dockable with dockpanel suite reference. Is that do-able or any other suggestion of better design?
Right now the treeview is on the dockpanel and the red box part is a usercontrol placed in the same dockpanel. I tried to put the redbox as another form but I can't place it as it is in the picture. Also, this winform is need to be responsive so I put in the redbox part in a table layout panel.winform design and not familiar actually with the dockpanel suite reference. If there is a beginner tutorial that I can refer to, it would be much appreciated.
Current design:
There are two approach to your problem. First is dirty one and second elegant one. By dirty and elegant i mean way they display. Method they work are both same.
I will explain to you how to do it on empty form and you just implement that in your populated one.
First create new form.
Add 2 or more GroupBoxes to it
Add some items inside them (just to see if it works)
At the top of the each boxes add Button which will toggle visibility
Our form now looks like this and let's look of code behind it.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace Test
{
public partial class TestForm : Form
{
// This is property
bool ShowFirstGroupBox
{
get
{
// We let user get our property from private variable
return _ShowFirstGroupBox;
}
set
{
// When user change this property we do something based on that
switch(value)
{
case true:
groupBox1.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox1.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowFirstGroupBox = value;
}
}
bool ShowSecondGroupBox
{
get
{
return _ShowSecondGroupBox;
}
set
{
switch (value)
{
case true:
groupBox2.Size = new Size(groupBox1.Width, FirstGroupBoxDefaultHeight);
break;
case false:
groupBox2.Size = new Size(groupBox1.Width, 55);
break;
}
_ShowSecondGroupBox = value;
}
}
// We store our boxes current state ( TRUE = shown, FALSE = HIDDEN )
bool _ShowFirstGroupBox = true;
bool _ShowSecondGroupBox = true;
// We store our default height for groupboxes
int FirstGroupBoxDefaultHeight;
int SecondGroupBoxDefaultHeight;
public TestForm()
{
InitializeComponent();
// Assigning default height of our groupboxes
FirstGroupBoxDefaultHeight = groupBox1.Height;
SecondGroupBoxDefaultHeight = groupBox2.Height;
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowFirstGroupBox = !(_ShowFirstGroupBox); // This sets our property value to opposite of this boolean
}
private void button1_Click_1(object sender, EventArgs e)
{
ShowSecondGroupBox = !(_ShowSecondGroupBox); // This sets our property value to opposite of this boolean
}
}
}
Now when we have code like this and press button it will collapse groupbox.
NOTE: Controls under groupbox are still on place but just hidden since they are child of groupbox and everything outside of bounds is not visible to user.
This is dirty way since i would like to display it much prettier with MINUS sign on the right side of the groupbox title so i do not have button inside it. To do this you would need to create custom control which inherits groupbox, add button to it and position it in title bar and create event for it. It is easy if you have ever tried creating custom controls but if you haven't and you think dirty approach is okay with you then do not try it.
Hey so I am attempting to create a form in which there are two buttons (acting as tabs) on the side in which when one is pressed specific controls are shown and when the other is pressed, another set are shown.
I have gotten this to work very well however I have run into an issue when about to create my second set of controls, how am I going to draw them (in designer) ontop of current controls (it's fine during runtime)? So my question is, how can I make this work. Current (possibly) important code:
private void CheatButton_Click(object sender, EventArgs e)
{
CheatControls(true);
ColorControls(false);
CheatButton.Normalcolor = Color.FromArgb(51, 51, 51);
ColorButton.Normalcolor = Color.FromArgb(61, 61, 61);
}
private void ColorButton_Click(object sender, EventArgs e)
{
CheatControls(false);
ColorControls(true);
CheatButton.Normalcolor = Color.FromArgb(61, 61, 61);
ColorButton.Normalcolor = Color.FromArgb(51, 51, 51);
}
private void CheatControls(bool b)
{
TriggerSwitch.Visible = b;
TriggerLabel.Visible = b;
BhopSwitch.Visible = b;
BhopLabel.Visible = b;
GlowSwitch.Visible = b;
GlowLabel.Visible = b;
RecoilSwitch.Visible = b;
RecoilLabel.Visible = b;
}
private void ColorControls(bool c)
{
}
My windows form application with an understandable graphic
Put all your cheat controls in a custom UserControl and all your color controls in a different custom UserControl. You can edit the different control sets easily in the designer, and in your code you can hide/show them more easily by setting the appropriate UserControl's visibility rather than setting the visibility of a bunch of controls individually. Here's an (admittedly old) example of creating a UserControl: msdn.microsoft.com/en-us/library/aa302342.aspx
When you create a UserControl in Visual Studio, you can add the controls to it using the designer. In your form with the tab buttons, you would add instances of the two UserControls that you created. Since UserControl derives from Control, it has a Visible property. So, in your CheatControls(bool b) method, your implementation would be simplified to something like _myCheatControls.Visible = b;. I haven't watched the whole thing, but this video might help, too: youtube.com/watch?v=l5L_q_jI494
You can use
XanderUI
Simply add a SuperButton(acts as a tab button) and when its clicked show a panel with your controls in it
EG -
private void ShowControlSet(int ControlSet)
{
panel1.visible = false;
panel2.visible = false;
if (ControlSet == 1) panel1.visible = true;
if (ControlSet == 2) panel2.visible = true;
}
// To show a panel use
ShowControlSet(1);
Your also able to use BringToFront() instead of making each panel invisible / visible but you need to anchor or dock the panels correctly
asides the visibility, what you can do is get the position of the buttons and st them when hiding and showing the other buttons
just set the top and left positions, ensuring the buttons are the same size.
I have a form with three panels.
I want the top two to be a fixed height, and bottom one to fill the rest of the space.
The dialog is resizable, so all should change width on resixze, and bottom one should change height.
This is important, the user must be able to stretch the form, as well as the program through code.
If I set a panel to visible = false, I want the form height to shrink so the others stay the same height.
If I set a panel to visible = true, I want the form height to grow by the height of the panel.
I will control the hiding/showing of the panels with buttons. The idea is I show certain panels for "advanced" mode in my form, and hide them for "simple" mode. I cannot have a bunch of blank space if I hide a panel, and I want the form to shrink a bunch for simple mode.
I tried doing this with panels docked to top, but a form resize by the user will not change a panel height. So that is the main trick I am asking for help on.
Anyone in this kind of situation can use the below styling:
Use 2-3 Panel to Group different Controls and place them in a single parent control say a GroupBox.
Make all the child panels Dock to the same side say "Top".
if any of the panel is jumping over another due to similar docking. In Visual Studio, go to menu View > Other Windows > Document Outline and Set the display order. (https://msdn.microsoft.com/en-us/library/46xf4h0w%28v=vs.80%29.aspx)
Set the Panel property as follows:
AutoSize: true
AutoSizeMode: GrowAndShrink
Once the panel is not visible, other panel will take away the empty space.
Hope this helps!!!
the other posts are close, there is a detail missing that I included in the solution I came up with. Its a flag to tell if the sized event was caused by a user form resize, or the program doing it when a panel is shown or hidden.
For this solution, make a form with 4 panels.
Set dock to top for all panels. Do not set any autosizing for panels or form.
Also make two buttons and place on top panel, or any panel that you will not be hiding.
The code below shows how to handle the resized event, and the showing hiding buttons.
I made them hide/show panel 2, but the code should work for any panel.
namespace ProgTesting {
public partial class Form5 : Form {
private bool doNothing = false;
public Form5() {
InitializeComponent();
cmdAdvanced.Visible = false;
}
private void cmdSimple_Click(object sender, EventArgs e) {
if (panel2.Visible) {
panel2.Visible = false;
doNothing = true;
this.MinimumSize = new Size(this.Width, this.Height - panel2.Height);
this.Height = this.Height - panel2.Height;
doNothing = false;
cmdSimple.Visible = false;
cmdAdvanced.Visible = true;
}
}
private void cmdAdvanced_Click(object sender, EventArgs e) {
if (!panel2.Visible) {
panel2.Visible = true;
doNothing = true;
this.Height = this.Height + panel2.Height;
this.MinimumSize = new Size(this.Width, this.Height);
doNothing = false;
cmdAdvanced.Visible = false;
cmdSimple.Visible = true;
}
}
private void Form5_SizeChanged(object sender, EventArgs e) {
if (!doNothing)
if (panel2.Visible)
panel3.Height = this.ClientSize.Height - panel1.Height - panel2.Height - panel4.Height;
else
panel3.Height = this.ClientSize.Height - panel1.Height - panel4.Height;
}
}
}
You do have to manage the heights going on, which is a pain but gives you control. Some shots of it working:
It sounds like what you are looking for is an Expander. Essentially a control that consists of a header and a content area, where clicking on the header toggles the content area between visible and collapsed.
I'm not 100% certain if an Expander control will automatically adjust the height of a form when it expands/collapses though. You may need to hook up an event handler to the Expander to manually adjust the height of your form when the Expander collapses.
Try looking at the Stack Overflow Question Add an expander (collapse/expand) to a Panel WinForm. There are a number of links from that question about implementing an Expander in Windows Forms, including some that provide full source code.
Update:
I've knocked up a quick demo that will accomplish what you want, in a very primitive way, not using any of the various Expander controls out there. I think that while you will find the Expanders useful, I doubt they will adjust the size of the container they are inside, unless you write some adjustment code like I have below.
Create a form that looks like this:
The two text boxes are anchored Left, Top, Right.
The toggle button is anchored Left, Top, named btnTogglePanel.
The magenta panel is anchored Left, Top, Right, Bottom, named pnlToggled.
The bottom button is anchored Right, Bottom.
Then in the code behind for the form:
public partial class ToggleableExpanderForm : Form
{
public ToggleableExpanderForm()
{
InitializeComponent();
SizeChanged += (s, args) =>
{
if (_LastSize.HasValue)
{
var diff = Size - _LastSize.Value;
if (_LastHeight.HasValue
&& !IgnoreNextResizeForLastHeightAdjustment)
{
_LastHeight += diff.Height;
}
}
_LastSize = Size;
};
}
private Size? _LastSize;
private bool IgnoreNextResizeForLastHeightAdjustment = true;
private int? _LastHeight;
private void btnTogglePanel_Click(object sender, EventArgs e)
{
var newVisibility = !pnlToggled.Visible;
int heightAdjustment = 0;
if (newVisibility)
{
if (_LastHeight.HasValue)
{
heightAdjustment = _LastHeight.Value;
_LastHeight = null;
}
}
else
{
_LastHeight = pnlToggled.Height;
heightAdjustment = -pnlToggled.Height;
}
pnlToggled.Visible = newVisibility;
IgnoreNextResizeForLastHeightAdjustment = true;
Height += heightAdjustment;
}
}
Essentially you adjust the height of the form manually when the toggle button is clicked, based on whether or not the panel is hiding/showing. You also need to take into account of what will happen when the user resizes the form when the panel is invisible, which is where the cruft around listening to the SizeChanged event comes in. You need the answer to "how MUCH has the size changed" and then you adjust your previously stored panel height as appropriate.
I don't imagine the above code is perfect, and I haven't tested it in every use case, but it gets the basic job done.
One way to go about it is to use a TableLayoutPanel for the top two panels.
The steps below will give you the resizing desired when the user resizes the form.
Start by created a TableLayoutPanel (TLP) and shrink it down from the default 2 columns, 2 rows to just 2 columns, 1 row.
Anchor it to Top, Left, and Right
Now size the TLP to fit your top two panels and place each panel in a cell of the TLP.
Anchor these two panels to all sides.
Position the 3rd panel (Panel3) below the TLP to your liking and anchor it to all sides.
To handle the hiding of Panel3 some logic will need to be added to the appropriate button_Click event. Determine what size you would like the "minimized" height to be and then just store the form size when Panel3 is visible and restore the height when it's clicked again. It should look something like this.
private void button1_Click(object sender, EventArgs e)
{
if (panel3.Visible)
{
// make invisible
panel3.Visible = false;
// storedHeight is a private member of the Form
storedHeight = Form1.ActiveForm.Height;
Form1.ActiveForm.Height = minimumHeight; // Set to predetermined minimum height
}
else
{
// make visible
panel3.Visible = true;
Form1.ActiveForm.Height = storedHeight;
}
}
Now when you hide Panel3 the form will shrink to the size of the TLP, then grow again when Panel3 is visible. Also the top panels will expand in width, but not height. You will need to change the MinSize properties of the form and its value will have to be dynamically adjusted depending on whether Panel3 is visible or not.
I'm trying to extend TextBox to add a Label to the left of it and treat it as one Control so I don't have to keep track of both of their sizes, locations, etc.
I've created a TextBoxWithLabel class that extends Control and has TextBox and Label fields, but I'm not really sure what to do for onPaint() - do I have to tell it to manually draw both items? If so, how? I'm guessing the default inherited behaviour doesn't go so far as 'check if I contain any child Controls and if I do, draw them'...
Is this even the best way to do it? I previously had my class extend TextBox and just added the Label field, but of course that didn't get added to the Panel containing the TextBoxWithLabel and so wasn't drawn.
Any suggestions or pokes in the right direction appreciated.
Thanks,
Alex
The typical approach here is a UserControl in which you put both the label and the text box. It is painful though, you have to add a lot of the properties and events of the text box to the user control so it at least resembles a text box. Ugly boilerplate code.
Another way to do it is to make a custom text box that sneaks in a label control on the parent. That completely behaves like a TextBox without having to do any work. Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form. Set the Description property to the text you want to see appear in the label.
using System;
using System.Drawing;
using System.Windows.Forms;
class MyTextBox : TextBox {
private Label label;
public MyTextBox() {
label = new Label();
label.AutoSize = true;
label.Font = this.Font;
label.Location = this.Location;
label.Resize += new EventHandler(label_Resize);
}
protected override void OnParentChanged(EventArgs e) {
// Keeps label on the same parent as the text box
base.OnParentChanged(e);
label.Parent = this.Parent; // NOTE: no dispose necessary
}
private void moveLabel() {
// Keep label right-aligned to the left of the text box
label.Location = new Point(this.Left - label.Width - 10, this.Top);
}
private void label_Resize(object sender, EventArgs e) {
moveLabel();
}
protected override void OnLocationChanged(EventArgs e) {
base.OnLocationChanged(e);
moveLabel();
}
public string Description {
get { return label.Text; }
set { label.Text = value; }
}
public override Font Font {
get { return base.Font; }
set { base.Font = label.Font = value; }
}
}
Did you consider using a UserControl? The benefit of a usercontrol is that you can easily put your label and textbox with correct relative positioning.
Custom Control - An extension to an existing control
User Control - A composition of multiple existing controls
Choose your candidate.