I have a .NET application with a StatusStrip holding three ToolTipStatusLabels. The Text of the labels are filled from the application as they show the status. For some circumstances they can hold an empty text.
When I resize the window, the ToolTipStatusLabels are hidden when they cannot be fit in the StatusStrip. I would like to have the text truncated when the label cannot be fit in the StatusStrip. The default behavior to hide the label makes it difficult to distinguish between empty text or hidden label.
To indicate that the text is truncated automatically, this should be indicated with an ellipsis (...). How can this be done?
Set the label's Spring property to True to get is to adjust its size automatically. To get ellipses you'll need to override the painting. Add a new class to your project and paste the code shown below. Compile. You'll get the new SpringLabel control in the status strip designer dropdown list.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[ToolStripItemDesignerAvailability(ToolStripItemDesignerAvailability.StatusStrip)]
public class SpringLabel : ToolStripStatusLabel {
public SpringLabel() {
this.Spring = true;
}
protected override void OnPaint(PaintEventArgs e) {
var flags = TextFormatFlags.Left | TextFormatFlags.EndEllipsis;
var bounds = new Rectangle(0, 0, this.Bounds.Width, this.Bounds.Height);
TextRenderer.DrawText(e.Graphics, this.Text, this.Font, bounds, this.ForeColor, flags);
}
}
You'll need to do more work if you use the Image or TextAlign properties.
Related
How to Override my controls using C#?
Need to set button property like
Font(Name => Segoe UI, style => Regular, size => 10), height => 50px, width => 250px, back color => green
by default.
How to use override method for respected button properties.
Note: I am going to use windows control library controls, to my projects.
Thanks in advance.
you can make your custom control for overriding with your default properties.
Sample button code for custom button:
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace DemoControls
{
[ToolboxItem(true)]
public class SimpleButton : Button
{
public SimpleButton()
{
Font = new Font("Segoe UI", 10, FontStyle.Regular);
Height = 50;
BackColor = DefaultBackColor;
}
}
}
It will show control in your toolbox when you build your project then you have to use this SimpleButton in your project where you want
This question already has answers here:
Word wrap for a label in Windows Forms
(20 answers)
Closed 9 years ago.
Is there a way to do a word wrap in a .NET label control?
I know there is an alternate way of using a TextBox, make property BorderStyle to none, property ReadOnly to true and set property WordWrap and property Multiline to true.
Is there something for a label?
Change your maximum size,
label1.MaximumSize = new Size(100, 0);
And set your autosize to true.
label1.AutoSize = true;
That's it!
Just set Label AutoSize property to False. Then the text will be wrapped and you can re-size the control manually to show the text.
Refer to Automatically Wrap Text in Label. It describes how to create your own growing label.
Here is the full source taken from the above reference:
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
public class GrowLabel : Label {
private bool mGrowing;
public GrowLabel() {
this.AutoSize = false;
}
private void resizeLabel() {
if (mGrowing) return;
try {
mGrowing = true;
Size sz = new Size(this.Width, Int32.MaxValue);
sz = TextRenderer.MeasureText(this.Text, this.Font, sz, TextFormatFlags.WordBreak);
this.Height = sz.Height;
}
finally {
mGrowing = false;
}
}
protected override void OnTextChanged(EventArgs e) {
base.OnTextChanged(e);
resizeLabel();
}
protected override void OnFontChanged(EventArgs e) {
base.OnFontChanged(e);
resizeLabel();
}
protected override void OnSizeChanged(EventArgs e) {
base.OnSizeChanged(e);
resizeLabel();
}
}
Ironically, turning off AutoSize by setting it to false allowed me to get the label control dimensions to size it both vertically and horizontally which effectively allows word-wrapping to occur.
If you open the dropdown for the Text property in Visual Studio, you can use the enter key to split lines. This will obviously only work for static text unless you know the maximum dimensions of dynamic text.
If you want some dynamic sizing in conjunction with a word-wrapping label you can do the following:
Put the label inside a panel
Handle the ClientSizeChanged event for the panel, making the
label fill the space:
private void Panel2_ClientSizeChanged(object sender, EventArgs e)
{
label1.MaximumSize = new Size((sender as Control).ClientSize.Width - label1.Left, 10000);
}
Set Auto-Size for the label to true
Set Dock for the label to Fill
You can use a TextBox and set multiline to true and canEdit to false .
When I add my UserControls to a FlowLayoutPanel, they display properly. When I change the Dock or Anchor properties on the UserControls before adding them, they are still added but do not render.
According to "How to: Anchor and Dock Child Controls" this should be possible.
I can tell that the controls are added (despite not drawing) because adding enough of them causes a vertical scrollbar to appear.
Setting the "Dock" property of the UserControls to "Left" or "None" will cause them to render, but none of the other options.
Setting the "Anchor" property on the UserControls to anything but Top | Left does not render.
Setting the dock before or after adding the control makes no difference (Add, Dock vs. Dock, Add).
The FlowLayoutPanel is itself is docked (Fill), has FlowDirection set to TopDown, has WrapContents set to false, has AutoScroll set to true, and is otherwise default.
I am using .NET 3.5.
In answer to a comment, the two commented lines are the locations I tried to change the dock. The second spot definitely makes more sense, but I tried the other because it couldn't hurt.
public void CreateObjectControl( object o )
{
ObjectControl oc = new ObjectControl();
oc.MyObject = o;
//This was a spot I mentioned:
//oc.Dock = DockStyle.Fill;
ObjectDictionary.Add( o, oc );
flowLayoutPanel1.Controls.Add( oc );
//This is the other spot I mentioned:
oc.Dock = DockStyle.Fill;
}
try using SuspendLayout and Resumelayout function for the controls before making any amendments which need rendering for proper viewing.
You could see the code from Designer.cs for that particular control
Syntax
control.SuspendLayout();
{Your code for designer amendments}
control.resumeaLayout();
I think I may have found a workaround (read: dirty trick) ... this answer helped to point me in the right direction. Here's an excerpt from the MS article that you also linked to:
For vertical flow directions, the FlowLayoutPanel control calculates the width of an implied column from the widest child control in the column. All other controls in this column with Anchor or Dock properties are aligned or stretched to fit this implied column.
The behavior works in a similar way for horizontal flow directions. The FlowLayoutPanel control calculates the height of an implied row from the tallest child control in the row, and all docked or anchored child controls in this row are aligned or sized to fit the implied row.
This page does not specifically mention that you can't Dock/Anchor the tallest/widest control. But as this control defines the layout behaviour of the FlowLayoutPanel, and thus influences the way all other sibling controls are displayed, it is well possible that Dock and Anchor don't work properly for that 'master control'. Even though I can't find any official documentation regarding that, I believe it to be the case.
So, which options do we have? At runtime, we could add a panel control of height 0 and width of the FlowLayoutPanel client area before you add your usercontrol. You can even set that panel's visibility to false. Subscribing to some Resize/Layout events of the FlowLayoutPanel to keep that panel's size will to the trick. But this does not play nicely at design time. The events won't fire and thus you can't really design the surface the way you want it to look.
I'd prefer a solution that "just works" at design time as well. So, here's an attempt at an "invisible" control that I put together, to fix the controls resizing to zero width if no other control is present. Dropping this as first control onto the FlowLayoutPanel at design time seems to provide the desired effect, and any control subsequently placed on the FlowLayoutPanel is anchorable to the right without shrinking to zero width. The only problem is that, once this invisible control is there, it seems I can't remove it anymore via the IDE. It probably needs some special treatment using a ControlDesigner to achieve that. It can still be removed in the form's designer code though.
This control, once placed onto the FlowLayoutPanel, will listen for resize events of it's parent control, and resize itself according to the ClientSize of the parent control. Use with caution, as this may contain pitfalls that didn't occur to me during the few hours I played with this. For example, I didn't try placing controls that were wider than the FlowLayoutPanel's client area.
As a side note, what will still fail is trying to anchor to the bottom, but that wasn't part of the question ;-)
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
namespace ControlTest
{
public sealed class InvisibleControl : Control
{
public InvisibleControl()
{
TabStop = false;
}
#region public interface
// Reduce the temptation ...
public new AnchorStyles Anchor
{
get { return base.Anchor; }
set { base.Anchor = AnchorStyles.None; }
}
public new DockStyle Dock
{
get { return base.Dock; }
set { base.Dock = DockStyle.None; }
}
// We don't ever want to move away from (0,0)
public new Point Location
{
get { return base.Location; }
set { base.Location = Point.Empty; }
}
// Horizontal or vertical orientation?
private Orientation _orientation = Orientation.Horizontal;
[DefaultValue(typeof(Orientation), "Horizontal")]
public Orientation Orientation
{
get { return _orientation; }
set
{
if (_orientation == value) return;
_orientation = value;
ChangeSize();
}
}
#endregion
#region overrides of default behaviour
// We don't want any margin around us
protected override Padding DefaultMargin => Padding.Empty;
// Clean up parent references
protected override void Dispose(bool disposing)
{
if (disposing)
SetParent(null);
base.Dispose(disposing);
}
// This seems to be needed for IDE support, as OnParentChanged does not seem
// to fire if the control is dropped onto a surface for the first time
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
ChangeSize();
}
// Make sure we don't inadvertantly paint anything
protected override void OnPaint(PaintEventArgs e) { }
protected override void OnPaintBackground(PaintEventArgs pevent) { }
// If the parent changes, we need to:
// A) Unsubscribe from the previous parent's Resize event, if applicable
// B) Subscribe to the new parent's Resize event
// C) Resize our control according to the new parent dimensions
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
// Perform A+B
SetParent(Parent);
// Perform C
ChangeSize();
}
// We don't really want to be resized, so deal with it
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
ChangeSize();
}
#endregion
#region private stuff
// Make this a default handler signature with optional params, so that this can
// directly subscribe to the parent resize event, but also be called without parameters
private void ChangeSize(object sender = null, EventArgs e = null)
{
Rectangle client = Parent?.ClientRectangle ?? new Rectangle(0, 0, 10, 10);
Size proposedSize = _orientation == Orientation.Horizontal
? new Size(client.Width, 0)
: new Size(0, client.Height);
if (!Size.Equals(proposedSize)) Size = proposedSize;
}
// Handles reparenting
private Control boundParent;
private void SetParent(Control parent)
{
if (boundParent != null)
boundParent.Resize -= ChangeSize;
boundParent = parent;
if (boundParent != null)
boundParent.Resize += ChangeSize;
}
#endregion
}
}
I want to use a tab control and have the tabs displayed on the left, as opposed to at the top. I have set the alignment to the left and the tabs are displayed there. However, how do I get the text to be displayed on the tab, vertically? I have looked at the msdn and it gives an example of a left aligned tab control but the tab label is still displayed horisontally!
The other thing, does anybody know how to use the tab control with left aligned tabs with the default layout so that it looks better?
Please no third party apps unless they are free, and yes I have looked at code project already.
Thanks, R.
It is an age-old bug in the visual styles renderer for the native Windows tab control. It only supports tabs at the top, the Microsoft programmer that worked on it was run over by a bus before she could finish the job, I guess.
The only thing you can do about it is selectively turn off visual styles for the control. 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, replacing the original.
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
public class FixedTabControl : TabControl {
[DllImportAttribute("uxtheme.dll")]
private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist);
protected override void OnHandleCreated(EventArgs e) {
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}
}
If you create your own DrawItem event, you can manually write the tab headers. You could use this process:
1) Set the following properties of the TabControl:
Property | Value
----------|----------------
Alignment | Right (or left, depending on what you want)
SizeMode | Fixed
DrawMode | OwnerDrawFixed
2) Set the ItemSize.Width property to 25 and the ItemSize.Height property to 100. Adjust these values as you want, but remember that basically, the width is the height and vice versa.
3) Add an event handler for the DrawItem event and add the following code:
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Brush _TextBrush;
// Get the item from the collection.
TabPage _TabPage = tabControl1.TabPages[e.Index];
// Get the real bounds for the tab rectangle.
Rectangle _TabBounds = tabControl1.GetTabRect(e.Index);
if(e.State == DrawItemState.Selected)
{
// Draw a different background color, and don't paint a focus rectangle.
_TextBrush = new SolidBrush(Color.Red);
g.FillRectangle(Brushes.Gray, e.Bounds);
}
else
{
_TextBrush = new System.Drawing.SolidBrush(e.ForeColor);
e.DrawBackground();
}
// Use our own font. Because we CAN.
Font _TabFont = new Font("Arial", 10, FontStyle.Bold, GraphicsUnit.Pixel);
// Draw string. Center the text.
StringFormat _StringFlags = new StringFormat();
_StringFlags.Alignment = StringAlignment.Center;
_StringFlags.LineAlignment = StringAlignment.Center;
g.DrawString(_TabPage.Text, _TabFont, _TextBrush,
_TabBounds, new StringFormat(_StringFlags));
}
4) Profit!
(original source: http://en.csharp-online.net/TabControl)
Does a smart textbox control (WinForms) exists that can display a path depending on the textbox width. For example, if the path is short it will display the entire path (C:\myfile.txt), but if the path is long it will display the start and end (C:\SomeFolder...\foo\MyFile.txt). The length of the characters displayed should be calculated (dynamically) by the textbox using its width. Any commercial or open source suggestions are welcome. Thank you very much.
Yes, it's a built-in capability of the TextRenderer.DrawText() method. One of its overloads accepts a TextFormatFlags argument, you can pass TextFormatFlags.PathEllipsis. Doing this for a TextBox is not appropriate, the user cannot reasonably edit such an abbreviated path, you would have no idea what the original path might be. A Label is the best control.
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. Don't make it too small.
using System;
using System.ComponentModel;
using System.Windows.Forms;
class PathLabel : Label {
[Browsable(false)]
public override bool AutoSize {
get { return base.AutoSize; }
set { base.AutoSize = false; }
}
protected override void OnPaint(PaintEventArgs e) {
TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.PathEllipsis;
TextRenderer.DrawText(e.Graphics, this.Text, this.Font, this.ClientRectangle, this.ForeColor, flags);
}
}