AutoEllipsis=true affects the vertical positioning of the text - c#

I have a label with AutoEllipsis = true and TextAlign = ContentAlignment.MiddleLeft. When I enter a text that is not extending the label width, the text is vertically aligned to the middle of the label.
However, when the text extends the label width the text is not aligned to the middle, but top aligned instead.
Why is it behaving this way, and is there a way to keep the text vertically center aligned?

I see it. This looks like a limitation in the underlying winapi, DrawTextEx(). Which doesn't get a lot of help from the Label class, it doesn't turn on the DT_SINGLELINE option (aka TextFormatFlags.SingleLine) since it is capable of rendering multiple lines. DrawTextEx() documents that this is required to get vertically centered text (DT_VCENTER). So the real bug is that it shouldn't be centered at all :) Do note that you do get centered text when you grow the label vertically.
The simplest way to work around it is by setting the label's UseCompatibleTextRendering property to True.

What I have done is set the top and bottom of the margin property to 3 and it worked well.
So have your margin be (3,3,3,3)!

One way to solve this is by implementing a custom control that overrides the OnPaint method and does not call the base method.
public class LabelEx : Label {
protected override void OnPaint(PaintEventArgs e) {
var flags = TextFormatFlags.SingleLine | TextFormatFlags.VerticalCenter | TextFormatFlags.WordEllipsis;
TextRenderer.DrawText(e.Graphics, Text, Font, ClientRectangle, ForeColor, flags);
}
}
One catch is that added event handlers will be ignored. (as a result of omitting the call to the base method)
Taken from here.

Related

In C#, in tooltip how to change different color for differnt part of text?

In the MS chart, I am displaying tooltip using below code.
ToolTip ToolTip = new ToolTip();
ToolTip .Show(" X value:"+s+"\nLine 1 Y value: =" + ss + "\nLine 2 Y value:=" + ss1, chart, (int)e.Location.X, (int)e.Location.Y);
I am able to set only one foreground color using ToolTip .ForeColor = System.Drawing.Color.Red;.
I am new to C#.
How to assign a different colour and draw text in custom tooltip class or how to use HTML renderer to achieve my requirement?
I could not assign a different colour for a different part of the tooltip text.
How to achieve it?
You can owner-draw the tooltip
Example:
ToolTip ToolTip = new ToolTip();
ToolTip.OwnerDraw = true;
ToolTip.Popup += (ss, ee) => { ee.ToolTipSize = new Size(200, 50); };
ToolTip.Draw += (ss, ee) =>
{
ee.DrawBackground();
ee.DrawBorder();
ee.Graphics.DrawString("Warning", Font, Brushes.Red, 10, 1);
ee.Graphics.DrawString(ee.ToolTipText, Font, Brushes.Black, 1, 22);
};
ToolTip.Show("Demo only", somecontrol..);
This is just a simple example; there are many more parameters to style the tooltip, including drawing stuff, images, brushes of all types, etc..
It is also recommended to use TextRenderer instead of the classic GDI+ DrawString.
Note how I set the Size in the PopUp event!
All sorts of formatting is possible with the text; for multiline text it is recommended to use an overload with bounding rectangle instead of x/y coordinates and maybe also alignment with a StringFormat. Do note though, that is is always tricky to embed formatted parts inside of a text.
Possible, but tedious to get really right, as always with GDI drawing. -
The basic trick is to determine a bounding rectangle first; this can be done with MeasureString.
The short answer would be "natively you simply can't" (Except you count drawing the label yourself as natively). But as always in programming there are creative ways to get the result you want.
The answer in the Question Orel suggested basically makes use of a renderer for HTML Markup to render the styled text inside your application.
If you have a look at the newer version of this library here they actually provide a WinForms ToolTip Control which accepts HTML Markup to render inside it's content area.
To use this renderer they provide a nuget package which makes installation trivial. Simply manage your projects nuget packages and search for HtmlRenderer.WinForms and install the latest version. (Check if it also installs the latest Version of HtmlRenderer.Core because it didn't on my end and I had to update the Core package)
After this rebuild your project to get the new controls in your designer toolbox.
To test the package I dragged a textbox and a HtmlToolTip onto my Form. To set the new toolTip you use it just like a normal WinForms tooltip.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.htmlToolTip1.SetToolTip(this.textBox1, "<h1 style=\"color:red\">Hello</h1><i style=\"color:blue\">World</i>");
}
}
Now you can style your toolTip content with HTML markup and change the foreground colors as you like:

GroupBox autosize

Take a GroupBox, put let say Label inside and then set AutoSizeMode = GrowAndShrink and AutoSize = true.
Two problems will arise:
There is a huge gap between Label and bottom of GroupBox (almost enough to fit another Label lol);
AutoSize doesn't respect the GroupBox.Text property.
Question is how to make GroupBox.AutoSize working properly? Properly means: minimum Width should be enough to fit GroupBox.Text, there should be no gaps below for unknown reason (it's not Margin, nor Padding and it looks pretty ugly).
I've tried to measure string length in OnPaint and setting MinimumSize right there. It works, but I have doubts about this, as if I would want to actually set MinimumSize later - it will be lost after repaint.
Update, here is screenshot:
You can get rid of the unwanted yellow space at the bottom by deriving a new class from GroupBox that adjusts the bottom edge a bit. In VB something like ...
Public Class BetterGroupBox
Inherits GroupBox
Public Overrides Function GetPreferredSize(ByVal proposedSize As Size) As Size
Dim ns = MyBase.GetPreferredSize(proposedSize)
Return New Size(ns.Width, ns.Height - 15)
End Function
End Class
It's simple that the location of your Label is fixed at some point other than (0,0), try this:
label1.Location = Point.Empty;
You may also want to try setting the Padding of your GroupBox to 0 for all (default is 3):
groupBox1.Padding = new Padding(0);
It seems as though the GroupBox control has a predefined padding of sorts when growing the control if AutoSize = true. That is, once a control (inside the GroupBox) gets within 20 pixels or so of the bottom of the GroupBox, the GroupBox starts growing. This causes a 20 pixel or so padding from the bottom of the bottom-most control to the bottom of the GroupBox (as highlighted in yellow by #Sinatr's attached image).
Based on my observations, the padding seems to be less when growing the Width of the GroupBox.
At any rate, you can do something like the following "get around" the issue:
public void MyFunction()
{
groupBox1.AutoSize = true;
// Do stuff (e.g., add controls to GroupBox)...
// Once all controls have been added to the GroupBox...
groupBox1.AutoSize = false;
// Add optional padding here if desired.
groupBox1.Height = myBottomMostControl.Bottom;
}

ToolStrip Rounded Corners

I am working on a Windows Form app (C#, .NET 4.0, VS 2010), where I have a pretty standard MainForm with a ToolStrip (GripStyle: Hidden, Dock: Top, RenderMode: ManagerRenderMode). The toolstrip contains a few basic items (ToolStripLabel, ToolStripSeparator, ToolStripSplitButton).
This is rendered as follows:
At first I simply wanted to add a 'bottom' border below the toolstrip, but I also noticed that this toolstrip is rendered with 'rounded corners' (you can see the right-hand-side top and bottom ones in the image), and a vertical gradient line.
How can I make these corners NOT rounded?
I tried:
public class MainFormToolStripRenderer : ToolStripProfessionalRenderer
{
protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e)
{
base.OnRenderToolStripBorder(e);
var y = e.ToolStrip.Height-1;
e.Graphics.DrawLine(new Pen(SystemColors.ControlDark, 1), new Point(0, y), new Point(e.ToolStrip.Width, y));
}
And wired it up via this.toolStrip_Actions.Renderer=new MainFormToolStripRenderer(); in my form initialization.
This gave me the bottom border, but didn't do anything for the rounded corners. Also, with the added bottom border, the rounded corners are more noticeable:
Next I tried drawing a rectangle during the same event handler above, to try (at least) to hide the rounded corners and vertical gradient behind a solid rectangular border. That didn't work because the available drawing area (e.AffectedBounds) is within the rounded borders.
I also tried to set the ToolStrip's RenderMode to System (and not use my renderer). In this case the toolstrip corners seem to fit snugly (rectangular), BUT the splitbutton within the toolbar seems to be broken (clicking the down arrow does not display the dropdown), for as-yet-unknown reasons, and the overall look-n-feel is a bit underwhelming (quite flat, until you hover on some buttons in the toolstrip).
I guess in the end I'd rather stick with the ManageeRenderedMode, or a custom renderer inheriting from the Professional one - but I need to get rid of the rounded corners.
Among others, I found this SO Q which seems to point close to what I'm looking at but didn't give me an answer for my case.
Thanks in advance
Try this in your renderer class:
public class MainFormToolStripRenderer : ToolStripProfessionalRenderer {
public MainFormToolStripRenderer() {
this.RoundedEdges = false;
}
}
Building on the accepted answer by LarsTech, you don't necessarily need to implement a new Renderer class, unless there are compelling reasons to do so.
You can do this as a one liner as follows:
toolStrip_Actions.Renderer = new ToolStripProfessionalRenderer() { RoundedEdges = false };
or since the default renderer for a ToolStrip with RenderMode set to ManagerRenderMode is already a ToolStripProfessionalRenderer, you may cast it as such and access the RoundedEdges property directly as follows:
((ToolStripProfessionalRenderer)toolStrip_Actions.Renderer).RoundedEdges = false;
As am05mhz mentioned, just select RenderMode > System and the rounded corners disappear:

How to resize a button depending on its text

In the process of translating an application with C# + Winforms, I need to change a button's text depending on the language.
My problem is the following :
Let's say I want to translate a button from "Hi all!" to "Bonjour tout le monde" !
As you can guess, the button's size won't be the same if I enter english text or french one... My question is "simple", how can I manage to resize the button on the fly so the text fits its content in the button ?
So far I got something like that !
[Hi all!]
[Bonjour]
There's absolutely no need to use the underlying Graphics object as the other posters have said.
If you set the button's AutoSize property to true, the AutoSizeMode to GrowAndShrink, and the AutoEllipsis to false, it will resize automatically to fit the text.
That being said, you may need to make several layout adjustments to make this change fit into your UI. You can adjust the button's padding to add space around the text, and you may want to place your buttons in a TableLayoutPanel (or something) to stop them from overlapping when they resize.
Edit:
#mastro pointed out that: AutoEllipsis is only valid when AutoSize is false (As explained in the documentation), so it can be safely ignored as long as the other three properties are set correctly.
Your best bet is to set the AutoSize property as described ach's answer
However if AutoSize isn't working for you, resizing the button in code is easy enough. You can just need to set the button's width. The trick is making it big enough to fit your text.
using(Graphics cg = this.CreateGraphics())
{
SizeF size = cg.MeasureString("Please excuse my dear aunt sally",this.button1.Font);
// size.Width+= 3; //add some padding .net v1.1 and 1.0 only
this.button1.Padding = 3;
this.button1.Width = (int)size.Width;
this.button1.Text = "Please excuse my dear aunt sally";
}
Try this:
Button.AutoSize = true;
Button.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
Button.TextAlign = ContentAlignment.MiddleLeft;
Button.Padding = new Padding(0, 0, 0, 0);
To enable a Button in WinForms grow and/or shrink depending on the size of the Text, you need to set the button's AutoSize property to True and the AutoSizeMode property to GrowAndShrink.
// C#
btn.AutoSize = true;
btn.AutoSizeMode = AutoSizeMode.GrowAndShrink;
' VB.NET
btn.AutoSize = True
btn.AutoSizeMode = AutoSizeMode.GrowAndShrink
Please note that the AutoSize property will only allow the button's size to grow if the AutoSizeMode property is set to GrowOnly; by changing the AutoSizeMode property to GrowAndShrink, the button will now automatically extend or reduce in width and height based on its Text property.
Also note that in setting the two properties as shown above, you can make use of new lines (Environment.NewLine or vbCrLf) in the Text property and the button will scale down as needed.
As Andrew Hanlon explains, you can set AutoSize = true.
When doing so, you can also attain a perfect layout of the buttons automatically by placing them on a FlowLayoutPanel.
The horizontal distance between them will always stay the same when the FlowDirection of the FlowLayoutPanel is LeftToRight or RightToLeft. You can adjust this distance by setting the Margin property of the buttons appropriately. You can create groups of buttons by increasing the left margin of buttons beginning a new group.
If you set the Dock property of the buttons to DockStyle.Fill, they will even grow their width automatically in order to fit to the widest button if the FlowDirection of the FlowLayoutPanel is TopDown or BottomUp.
btn.AutoSizeMode = AutoSizeMode.GrowOnly;
btn.AutoSize = true;
btn.Dock = DockStyle.Fill;
In addition to setting the AutoSize to true and the AutoSizeModeto GrowAndShrink, as suggested in the other answers, you may also need to set the TextImageRelation property, if you have set the button image, so that the text doesn't overlap the image.

C# have end of text priorities

I'm concatenating a string that sometimes is long enough for it not to fit in a label control. How can i make it autoscroll to the rightside so i always see the end of the string?
While I'm sure there are ways of doing, I have to ask, why? I think it would look and/or work very badly and probably confuse the user.
Why not have the text get trimmed with an ellipse (...) at the end and show a tooltip on the label?
using System.Windows.Forms;
var label = new Label();
label.AutoSize = false;
label.AutoEllipsis = true;
label.Text = "This text will be too long to display all together.";
var labelToolTip = new ToolTip();
labelToolTip.SetToolTip(label, label.Text);
Now the tooltip will show the full text when the user hovers over it. Since the text in the label will be truncated and end in an ellipse, the user should know to hover over for more info (usually the standard way).
The TextAlign property allows you to specify the alignment. If you right-justify it with this, the right side of the text will always be visible. However, if you want it to be left or center justified and still have the behavior you describe, I suspect you will need to perform some measurement using Graphics.MeasureString to determine if the text fits and change the alignment dynamically.
AFAIK there's no way to scroll a label. A hack would be to use a TextBox (read-only, turn off border) then use SendKeys.Send() to move the cursor to the end of the text. Something like:
textBox1.Focus();
SendKeys.SendWait("{END}");
To get the text to not show up as selected I had to change it's position in the tab order (so that it wasn't 1) but that may not be a problem in your case.

Categories

Resources