In WPF it has the default support for the vertical alignment for the TextBox control. but in Windows Forms there is no way to set the vertical alignment of the TextBox control.
In My case, I have using the multi-line text box and the text is need to be displayed on the bottom of the TextBox and it need to be maintain the alignment while typing on it.
I have tried to get the line count of the entered text and try to calculate the bounds of the text box based on the length of the text. but the line count is not get properly when editing the text with word wrap.
Can any one help me on this to maintain the vertical alignment of the TextBox while editing?
I have tried to change the location of the textbox using the suggestion given in that thread. when editing the text. When I try to edit the text the bounds is not updated properly and some part of the text is hidden in the text box. I have calculated the bounds based on the font size and text width.
Size textSize = TextRenderer.MeasureText(TextBoxText, this.textBoxControl.Font);
int textBoxTop = this.textBoxControl.Bounds.Top;
int nol = (textSize.Width > this.textBoxControl.Width) ? ((textSize.Width) / this.textBoxControl.Width) + 1 : 1;
{
if (nol > n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (top + (height - nol * textSize.Height) > top)
{
rect1.Y = top + (height - nol * textSize.Height);
rect1.Height = nol * textSize.Height;
this.textBoxControl.Bounds = rect1;
}
else
{
this.textBoxControl.Bounds = rect1;
}
}
else if (nol < n)
{
n = nol;
rect1 = this.textBoxControl.Bounds;
if (rect1.Y + nol * textSize.Height < top + height)
{
rect1.Y += textSize.Height - this.textBoxControl.Margin.Top;
rect1.Height -= textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
if (nol == 1)
{
rect1.Y = top + height - textSize.Height;
rect1.Height = textSize.Height;
//this.textBoxControl.Bounds = rect1;
}
this.textBoxControl.Bounds = rect1;
}
}
Its working fine while editing the text, but in some cases the nol Line count is calculated wrongly. How can I get the actual line count of the textbox including the wrapped lines.?
I have created a control that has a TextBox docked to the bottom of a panel that looks kinda like a TextBox:
// Make sure you have this.
using System.Linq;
public class BottomAlignTextBox : Panel
{
public BottomAlignTextBox()
{
this.BackColor = Color.White;
this.BorderStyle = (Application.RenderWithVisualStyles) ? BorderStyle.FixedSingle : BorderStyle.Fixed3D;
this.Size = new Size(200, 200);
this.Padding = new Padding(5, 0, 4, 2);
bottomAlignTextBox.Dock = DockStyle.Bottom;
bottomAlignTextBox.Multiline = true;
bottomAlignTextBox.WordWrap = true;
bottomAlignTextBox.AcceptsReturn = true;
bottomAlignTextBox.BorderStyle = BorderStyle.None;
bottomAlignTextBox.Height = 20;
bottomAlignTextBox.TextChanged += delegate
{
if (bottomAlignTextBox.Height < this.Height - 20)
{
if (TextRenderer.MeasureText(bottomAlignTextBox.Text, bottomAlignTextBox.Font).Width > bottomAlignTextBox.Width + 6)
{
string longestLine = bottomAlignTextBox.Lines.OrderByDescending(s => TextRenderer.MeasureText(s, bottomAlignTextBox.Font).Width).First();
bottomAlignTextBox.Text = bottomAlignTextBox.Text.Replace(longestLine, longestLine.Substring(0, longestLine.Length - 1) + Environment.NewLine + longestLine[longestLine.Length - 1]);
bottomAlignTextBox.Height += 19;
bottomAlignTextBox.SelectionStart = bottomAlignTextBox.Text.Length + 2;
bottomAlignTextBox.SelectionLength = 0;
}
}
};
this.Controls.Add(bottomAlignTextBox);
this.Click += delegate { bottomAlignTextBox.Focus(); };
}
public new string Text
{
get { return bottomAlignTextBox.Text; }
set { bottomAlignTextBox.Text = value; }
}
private TextBox bottomAlignTextBox = new TextBox();
}
I am not sure if that is entirely possible, but I think you can wrap the control with a Panel control or some sort and Dock it to the bottom of the wrapping Panel control? If the size needs to be dynamic, playing around the Anchor properties should work as well.
Related
Label is possible part text for left and part text to right?
int x = 5;
label1.Text = "MY TEXT FROM LEFT : " + x.ToString();
Where, x from right?
This Visual Studio 2013 and Windows Forms Application
My new idea:
string length = "";
for (int i = 0; i < 50; i++)
length += " ";
label1.Text = "MY TEXT FROM LEFT : " + length + x.ToString();
But, length of my window = ???
If I understand you correctly, perhaps something like this is what you're trying to achieve?
var leftString = "Left string:";
var rightString = "Right string";
var graphics = textBox1.CreateGraphics();
var leftStringWidth = (int) graphics.MeasureString(leftString, textBox1.Font).Width;
var rightStringWidth = (int) graphics.MeasureString(rightString, textBox1.Font).Width;
var spaceWidth = (int) graphics.MeasureString(" ", textBox1.Font).Width;
var padding = new string(' ',
(textBox1.Width - leftStringWidth - rightStringWidth) / spaceWidth);
textBox1.Text = leftString + padding + rightString;
Output
You could subscribe to the paint event to draw the underline and second string:
private void label1_Paint(object sender, PaintEventArgs e)
{
var rightString = "Right string";
var rightStringWidth = e.Graphics.MeasureString(rightString, label1.Font).Width;
var rightStringXLocation = label1.Width - rightStringWidth;
using (var brush = new SolidBrush(label1.ForeColor))
{
e.Graphics.DrawString(rightString, label1.Font, brush, new PointF(rightStringXLocation, 0));
var lineHeight = label1.Height - 5;
e.Graphics.DrawLine(new Pen(brush), e.Graphics.MeasureString(label1.Text, label1.Font).Width, lineHeight, rightStringXLocation, lineHeight);
}
}
To resize automatically with the window you will also need to set Anchor to Left, Right:
this.label1.Anchor = (AnchorStyles)(AnchorStyles.Left | AnchorStyles.Right);
Configure your label as follows:
Anchor: Top, Left, Right
Autosize: False
TextAlign: TopRight
And widen your label to window width. This way the text will be aligned to the right of the form.
UPDATE:
Try the following code to measure width and set appropriate number of underlines. Note that we measure 1000 of underlines to make it more precise. Button and Random are added for demonstration puproses. The result is not 100% precise, but you can't achieve more with just adding underline characters.
private Random _rnd = new Random(DateTime.Now.Millisecond);
private static float measureTextWidth(string text, Font font, Graphics g)
{
SizeF size = g.MeasureString(text, font);
return size.Width;
}
private void button1_Click(object sender, EventArgs e)
{
using (Graphics g = label1.CreateGraphics())
{
string leftText = "Some caption";
string rightText = new string('V', _rnd.Next(50));
float leftWidth = measureTextWidth(leftText, label1.Font, g);
float rightWidth = measureTextWidth(rightText, label1.Font, g);
float underlineWidth = measureTextWidth(new string('_', 1000), label1.Font, g );
underlineWidth = underlineWidth / 1000.0f;
float allSpacesWidth = this.Width - leftWidth - rightWidth;
int numberOfSpaces = (int)(allSpacesWidth / underlineWidth);
label1.Text = leftText + new string('_', numberOfSpaces) + rightText;
}
There is advanced method to measure string size if Graphics.MeasureString will be not precise enough:
https://www.codeproject.com/Articles/2118/Bypass-Graphics-MeasureString-limitations
If you can use 2 labels instead of one:
Place TableLayoutPanel (with docking or anchor as you need) on your form.
Panel should have 1 row and 2 columns (AutoSize)
Add 2 labels to panel (one with anchor Left second with anchor Right)
set "left text" to first label and "right text" to second one.
I've got a programatically created TableLayoutPanel, with each of its cells containing a Panel. Each Panel has a custom Label. (The Labels' Enabled property is set to false; not sure if that makes a difference.) I'd like to display the text of the Label whenever the user hovers over it with the mouse.
From what I've read, a ToolTip is a good way to do this, but I haven't been able to get it to work.
The TableLayoutPanel is name "tlp" for short and is a member of the form for easier access (likewise with the ToolTip, which is name "toolTip").
For now I'm just trying to get any kind of text. I'll replace my string here with the Label's text once I can get it to work.
private void hoverOverSpace(object sender, EventArgs e)
{
int row = tlp.GetRow((Panel)sender);
int col = tlp.GetColumn((Panel)sender);
toolTip.Show("Does this work?", tlp.GetControlFromPosition(col, row).Controls[0]);
//toolTip.Show("Does this work?", tlp.GetControlFromPosition(col, row));
}
Neither of my attempts to display the ToolTip have been successful. Am I doing something wrong/is there a better method for doing what I'm trying to accomplish?
EDIT: I've attempted to add the toolTip to each Panel but still nothing is happening
// Add Panels to TableLayoutPanel
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
// Create new Panel
Panel space = new Panel()
{
Size = new Size(45, 45),
Dock = DockStyle.Fill,
Margin = new Padding(0)
};
space.MouseClick += new MouseEventHandler(clickOnSpace);
CustomLabel info = new CustomLabel(false, 0, Color.White); // Create new CustomLabel
space.Controls.Add(info); // Add CustomLabel to Panel
tlp.Controls.Add(space, j, i); // Add Panel to TableLayoutPanel
toolTip = new ToolTip();
toolTip.SetToolTip(space, info.Text);
}
}
This answer is based on code presented in the answer to: tablelayoutPanel get cell location from mouse over, by: Aland Li Microsoft CSS.
#region GetPosition
// Modified from answer to: tablelayoutPanel get cell location from mouse over
// By: Aland Li Microsoft CSS
// https://social.msdn.microsoft.com/Forums/windows/en-US/9bb6f42e-046d-42a0-8c83-febb1dcf98a7/tablelayoutpanel-get-cell-location-from-mouse-over?forum=winforms
//The method to get the position of the cell under the mouse.
private TableLayoutPanelCellPosition GetCellPosition(TableLayoutPanel panel, Point p)
{
//Cell position
TableLayoutPanelCellPosition pos = new TableLayoutPanelCellPosition(0, 0);
//Panel size.
Size size = panel.Size;
//average cell size.
SizeF cellAutoSize = new SizeF(size.Width / panel.ColumnCount, size.Height / panel.RowCount);
//Get the cell row.
//y coordinate
float y = 0;
for (int i = 0; i < panel.RowCount; i++)
{
//Calculate the summary of the row heights.
SizeType type = panel.RowStyles[i].SizeType;
float height = panel.RowStyles[i].Height;
switch (type)
{
case SizeType.Absolute:
y += height;
break;
case SizeType.Percent:
y += height / 100 * size.Height;
break;
case SizeType.AutoSize:
y += cellAutoSize.Height;
break;
}
//Check the mouse position to decide if the cell is in current row.
if ((int)y > p.Y)
{
pos.Row = i;
break;
}
}
//Get the cell column.
//x coordinate
float x = 0;
for (int i = 0; i < panel.ColumnCount; i++)
{
//Calculate the summary of the row widths.
SizeType type = panel.ColumnStyles[i].SizeType;
float width = panel.ColumnStyles[i].Width;
switch (type)
{
case SizeType.Absolute:
x += width;
break;
case SizeType.Percent:
x += width / 100 * size.Width;
break;
case SizeType.AutoSize:
x += cellAutoSize.Width;
break;
}
//Check the mouse position to decide if the cell is in current column.
if ((int)x > p.X)
{
pos.Column = i;
break;
}
}
//return the mouse position.
return pos;
}
#endregion
It uses the TableLayoutPanelCellPosition computed by the referenced code to obtain the Control at that position (if any) and display its Text property as a ToolTip on the TableLayoutPanel.MouseHover event.
private void tableLayoutPanel1_MouseHover(object sender, EventArgs e)
{
Point pt = tableLayoutPanel1.PointToClient(Control.MousePosition);
TableLayoutPanelCellPosition pos = GetCellPosition(tableLayoutPanel1, pt);
Control c = tableLayoutPanel1.GetControlFromPosition(pos.Column, pos.Row);
if (c != null)
{
toolTip1.Show(c.Text, tableLayoutPanel1, pt, 500);
}
}
Edit:
I missed that the TLP is populated with controls with their Dock property set to DockStyle.Fill`. Such controls place placed in the TLP will receive the Mouse Events instead of the TLP. So as fix, add this method.
private void showtip(object sender, EventArgs e)
{
Point pt = tableLayoutPanel1.PointToClient(Control.MousePosition);
TableLayoutPanelCellPosition pos = GetCellPosition(tableLayoutPanel1, pt);
Control c = tableLayoutPanel1.GetControlFromPosition(pos.Column, pos.Row);
if (c != null && c.Controls.Count > 0)
{
toolTip1.Show(c.Controls[0].Text, tableLayoutPanel1, pt, 500);
}
}
Then wireup the each Panel and Label grouping like this:
this.panel4.MouseHover += new System.EventHandler(this.showtip);
this.label4.MouseHover += new System.EventHandler(this.showtip);
I'm using simple code to generate a grid (gridSize * gridSize fields with lines dividing them in column and row, basically a TicTacToe grid).
As I'm creating the panels dynamically during Form_Load, I need to also adjust the size of the form. However, setting it to gridSize * tileSize, gridSize * tileSize is not big enough - I found by experimentation that I need to add ~15 to width and ~40 to height for gridSize = 3 and tileSize = 120. Why is this?
Code below:
private void Form1_Load(object sender, EventArgs e)
{
const int tileSize = 120;
const int gridSize = 3;
/* Here: When setting size, I need to add 15 and 40? */
this.Size = new System.Drawing.Size(tileSize * gridSize + 15, tileSize * gridSize + 40);
// initialize the "board"
tictactoeFields = new Panel[gridSize, gridSize]; // column, row
// double for loop to handle all rows and columns
for (var n = 0; n < gridSize; n++)
{
for (var m = 0; m < gridSize; m++)
{
// create new Panel control which will be one
// tic tac toe field
var newPanel = new Panel
{
Size = new Size(tileSize, tileSize),
Location = new Point(tileSize * n, tileSize * m)
};
// add to our 2d array of panels for future use
tictactoeFields[n, m] = newPanel;
newPanel.BackColor = Color.White;
if(n != 0)
{
// Draw a line in front (to the left) of this panel
Panel leftSeparator = new Panel
{
Size = new Size(1, tileSize),
Location = newPanel.Location,
BackColor = Color.Black
};
Controls.Add(leftSeparator);
}
if(m != 0)
{
// Draw a line on top (above) this panel
Panel topSeparator = new Panel
{
Size = new Size(tileSize, 1),
Location = newPanel.Location,
BackColor = Color.Black
};
Controls.Add(topSeparator);
}
}
}
foreach(Panel pan in tictactoeFields)
{
// add to Form's Controls so that they show up
Controls.Add(pan);
}
}
The Size property is just a shorthand for setting the size of the Bounds property which includes nonclient elements such as scroll bars, borders, title bars, and menus.
What you should do is to set the size of the ClientRectangle property, or use the ClientSize shorthand.
There's also a DisplayRectangle property which includes padding, but in this case use the ClientRectangle property.
this.ClientSize = new Size((tileSize * gridSize), (tileSize * gridSize));
I have a custom control that zooms on a custom drawn document canvas.
I tried using AutoScroll but it was not giving satisfactory results. When I would set AutoScrollPosition and AutoScrollMinSize back to back (in any order) it would force a paint and cause jitter each time the zoom changes. I assume this was because it was calling an Update and not Invalidate when I modified both properties.
I am now manually setting the HorizontalScroll and VerticalScroll properties with AutoScroll set to false like so each time the Zoom level or the client size changes:
int canvasWidth = (int)Math.Ceiling(Image.Width * Zoom) + PageMargins.Horizontal;
int canvasHeight = (int)Math.Ceiling(Image.Height * Zoom) + PageMargins.Vertical;
HorizontalScroll.Maximum = canvasWidth;
HorizontalScroll.LargeChange = ClientSize.Width;
VerticalScroll.Maximum = canvasHeight;
VerticalScroll.LargeChange = ClientSize.Height;
if (canvasWidth > ClientSize.Width)
{
HorizontalScroll.Visible = true;
}
else
{
HorizontalScroll.Visible = false;
HorizontalScroll.Value = 0;
}
if (canvasHeight > ClientSize.Height)
{
VerticalScroll.Visible = true;
}
else
{
VerticalScroll.Visible = false;
VerticalScroll.Value = 0;
}
int focusX = (int)Math.Floor((FocusPoint.X * Zoom) + PageMargins.Left);
int focusY = (int)Math.Floor((FocusPoint.Y * Zoom) + PageMargins.Top);
focusX = focusX - ClientSize.Width / 2;
focusY = focusY - ClientSize.Height / 2;
if (focusX < 0)
focusX = 0;
if (focusX > canvasWidth - ClientSize.Width)
focusX = canvasWidth - ClientSize.Width;
if (focusY < 0)
focusY = 0;
if (focusY > canvasHeight - ClientSize.Height)
focusY = canvasHeight - ClientSize.Height;
if (HorizontalScroll.Visible)
HorizontalScroll.Value = focusX;
if (VerticalScroll.Visible)
VerticalScroll.Value = focusY;
In this case, FocusPoint is a PointF structure that holds the coordinates in the bitmap which the user is focused on (for example, when they mouse wheel to zoom in they are focusing on the current mouse location at that time). This functionality works for the most part.
What does not work is the scroll bars. If the user tries to manually scroll by clicking on either scroll bar, they both keep returning to 0. I do not set them anywhere else in my code. I have tried writing the following in the OnScroll() method:
if (se.ScrollOrientation == ScrollOrientation.VerticalScroll)
{
VerticalScroll.Value = se.NewValue;
}
else
{
HorizontalScroll.Value = se.NewValue;
}
Invalidate();
But this causes some very erratic behavior including flicking and scrolling out of bounds.
How am I supposed to write the code for OnScroll? I've tried the base.OnScroll but it didn't do anything while AutoScroll is set to false.
I ended up implementing my own custom scrolling by creating 3 child controls: an HScrollBar, a VScrollBar, and a Panel.
I hide ClientSize and ClientRectangle like so:
public new Rectangle ClientRectangle
{
get
{
return new Rectangle(new Point(0, 0), ClientSize);
}
}
public new Size ClientSize
{
get
{
return new Size(
base.ClientSize.Width - VScrollBar.Width,
base.ClientSize.Height - HScrollBar.Height
);
}
}
The layout is done in OnClientSizeChanged:
protected override void OnClientSizeChanged(EventArgs e)
{
base.OnClientSizeChanged(e);
HScrollBar.Location = new Point(0, base.ClientSize.Height - HScrollBar.Height);
HScrollBar.Width = base.ClientSize.Width - VScrollBar.Width;
VScrollBar.Location = new Point(base.ClientSize.Width - VScrollBar.Width, 0);
VScrollBar.Height = base.ClientSize.Height - HScrollBar.Height;
cornerPanel.Size = new Size(VScrollBar.Width, HScrollBar.Height);
cornerPanel.Location = new Point(base.ClientSize.Width - cornerPanel.Width, base.ClientSize.Height - cornerPanel.Height);
}
Each ScrollBar has their Scroll event subscribed to the following:
private void ScrollBar_Scroll(object sender, ScrollEventArgs e)
{
OnScroll(e);
}
And finally we can allow MouseWheel events to scroll with the following:
protected override void OnMouseWheel(MouseEventArgs e)
{
int xOldValue = VScrollBar.Value;
if (e.Delta > 0)
{
VScrollBar.Value = (int)Math.Max(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), 0);
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
else
{
VScrollBar.Value = (int)Math.Min(VScrollBar.Value - (VScrollBar.SmallChange * e.Delta), VScrollBar.Maximum - (VScrollBar.LargeChange - 1));
OnScroll(new ScrollEventArgs(ScrollEventType.ThumbPosition, xOldValue, VScrollBar.Value, ScrollOrientation.VerticalScroll));
}
}
For custom painting, you would use the following statement:
e.Graphics.TranslateTransform(-HScrollBar.Value, -VScrollBar.Value);
This worked perfectly without the glitches present when using AutoScroll.
I set the DrawMode to OwnerDrawText and tacked on to the DrawNode event, added my code to draw the text the way I want and all works well save for some odd black selection highlighting when a node is selected.
No problem, I added logic to check for if the node's state was highlighted and drew my own highlighting except the black highlighting gets added when a node is clicked, not just selected... The highlight gets drawn over by my rectangle once the mouse button is released but does get drawn and blinks...it's annoying. :/
Apparently I forgot to actually ask my question...How would one go about getting rid of the selection without completely handling the drawing?
In my experience you usually can't. Either you draw the item yourself or you don't. If you try to composite your graphics on top of those drawn by the control, you'll end up with glitches.
It is a bit of a pain because you have to handle focus rectangles, selection highlights, and drawing all the glyphs yourself.
On the plus side, Visual Styles can be used to do most of the work.
Here's some code that will get you most of the way there (it's incomplete, in that it uses some methods not included, and it doesn't render exactly what a normal treeview does because it supports grad filled items and columns, but should be a handy reference)
protected virtual void OnDrawTreeNode(object sender, DrawTreeNodeEventArgs e)
{
string text = e.Node.Text;
Rectangle itemRect = e.Bounds;
if (e.Bounds.Height < 1 || e.Bounds.Width < 1)
return;
int cIndentBy = 19; // TODO - support Indent value
int cMargin = 6; // TODO - this is a bit random, it's slaved off the Indent in some way
int cTwoMargins = cMargin * 2;
int indent = (e.Node.Level * cIndentBy) + cMargin;
int iconLeft = indent; // Where to draw parentage lines & icon/checkbox
int textLeft = iconLeft + 16; // Where to draw text
Color leftColour = e.Node.BackColor;
Color textColour = e.Node.ForeColor;
if (Bitfield.IsBitSet(e.State, TreeNodeStates.Grayed))
textColour = Color.FromArgb(255,128,128,128);
// Grad-fill the background
Brush backBrush = new SolidBrush(leftColour);
e.Graphics.FillRectangle(backBrush, itemRect);
// Faint underline along the bottom of each item
Color separatorColor = ColourUtils.Mix(leftColour, Color.FromArgb(255,0,0,0), 0.02);
Pen separatorPen = new Pen(separatorColor);
e.Graphics.DrawLine(separatorPen, itemRect.Left, itemRect.Bottom-1, itemRect.Right, itemRect.Bottom-1);
// Bodged to use Button styles as Treeview styles not available on my laptop...
if (!HideSelection)
{
if (Bitfield.IsBitSet(e.State, TreeNodeStates.Selected) || Bitfield.IsBitSet(e.State, TreeNodeStates.Hot))
{
Rectangle selRect = new Rectangle(textLeft, itemRect.Top, itemRect.Right - textLeft, itemRect.Height);
VisualStyleRenderer renderer = new VisualStyleRenderer((ContainsFocus) ? VisualStyleElement.Button.PushButton.Hot
: VisualStyleElement.Button.PushButton.Normal);
renderer.DrawBackground(e.Graphics, selRect);
// Bodge to make VisualStyle look like Explorer selections - overdraw with alpha'd white rectangle to fade the colour a lot
Brush bodge = new SolidBrush(Color.FromArgb((Bitfield.IsBitSet(e.State, TreeNodeStates.Hot)) ? 224 : 128,255,255,255));
e.Graphics.FillRectangle(bodge, selRect);
}
}
Pen dotPen = new Pen(Color.FromArgb(128,128,128));
dotPen.DashStyle = DashStyle.Dot;
int midY = (itemRect.Top + itemRect.Bottom) / 2;
// Draw parentage lines
if (ShowLines)
{
int x = cMargin * 2;
if (e.Node.Level == 0 && e.Node.PrevNode == null)
{
// The very first node in the tree has a half-height line
e.Graphics.DrawLine(dotPen, x, midY, x, itemRect.Bottom);
}
else
{
TreeNode testNode = e.Node; // Used to only draw lines to nodes with Next Siblings, as in normal TreeViews
for (int iLine = e.Node.Level; iLine >= 0; iLine--)
{
if (testNode.NextNode != null)
{
x = (iLine * cIndentBy) + (cMargin * 2);
e.Graphics.DrawLine(dotPen, x, itemRect.Top, x, itemRect.Bottom);
}
testNode = testNode.Parent;
}
x = (e.Node.Level * cIndentBy) + cTwoMargins;
e.Graphics.DrawLine(dotPen, x, itemRect.Top, x, midY);
}
e.Graphics.DrawLine(dotPen, iconLeft + cMargin, midY, iconLeft + cMargin + 10, midY);
}
// Draw Expand (plus/minus) icon if required
if (ShowPlusMinus && e.Node.Nodes.Count > 0)
{
// Use the VisualStyles renderer to use the proper OS-defined glyphs
Rectangle expandRect = new Rectangle(iconLeft-1, midY - 7, 16, 16);
VisualStyleElement element = (e.Node.IsExpanded) ? VisualStyleElement.TreeView.Glyph.Opened
: VisualStyleElement.TreeView.Glyph.Closed;
VisualStyleRenderer renderer = new VisualStyleRenderer(element);
renderer.DrawBackground(e.Graphics, expandRect);
}
// Draw the text, which is separated into columns by | characters
Point textStartPos = new Point(itemRect.Left + textLeft, itemRect.Top);
Point textPos = new Point(textStartPos.X, textStartPos.Y);
Font textFont = e.Node.NodeFont; // Get the font for the item, or failing that, for this control
if (textFont == null)
textFont = Font;
StringFormat drawFormat = new StringFormat();
drawFormat.Alignment = StringAlignment.Near;
drawFormat.LineAlignment = StringAlignment.Center;
drawFormat.FormatFlags = StringFormatFlags.NoWrap;
string [] columnTextList = text.Split('|');
for (int iCol = 0; iCol < columnTextList.GetLength(0); iCol++)
{
Rectangle textRect = new Rectangle(textPos.X, textPos.Y, itemRect.Right - textPos.X, itemRect.Bottom - textPos.Y);
if (mColumnImageList != null && mColumnImageList[iCol] != null)
{
// This column has an imagelist assigned, so we use the column text as an integer zero-based index
// into the imagelist to indicate the icon to display
int iImage = 0;
try
{
iImage = MathUtils.Clamp(Convert.ToInt32(columnTextList[iCol]), 0, mColumnImageList[iCol].Images.Count);
}
catch(Exception)
{
iImage = 0;
}
e.Graphics.DrawImageUnscaled(mColumnImageList[iCol].Images[iImage], textRect.Left, textRect.Top);
}
else
e.Graphics.DrawString(columnTextList[iCol], textFont, new SolidBrush(textColour), textRect, drawFormat);
textPos.X += mColumnWidthList[iCol];
}
// Draw Focussing box around the text
if (e.State == TreeNodeStates.Focused)
{
SizeF size = e.Graphics.MeasureString(text, textFont);
size.Width = (ClientRectangle.Width - 2) - textStartPos.X;
size.Height += 1;
Rectangle rect = new Rectangle(textStartPos, size.ToSize());
e.Graphics.DrawRectangle(dotPen, rect);
// ControlPaint.DrawFocusRectangle(e.Graphics, Rect);
}
}