I'm trying to set the Height of the form while I'm resizing it, if a condition is met. I have it set to only allow the width of the form to be altered manually using the code provided by in this answer.
I have a FlowLayoutPanel displaying a collection of PictureBox controls, each with a fixed Height of 50 pixels. Initially, the form's Height is 38 (Size.Height - ClientSize.Height) + 50 + 6 (Margin.Top + Margin.Bottom of an image) = 94.
If the controls overflow, by default the FlowLayoutPanel pushes them down onto a new line. What I want to do is resize the form when this happens, or when the form width is manually changed which might cause the controls to jump to the next line.
The following code works, and is called whenever a new control is added to the FlowLayoutPanel (itemPanel):
private void ResizeForm()
{
if (itemPanel.Controls.Count < 1) return;
var lastElement = itemPanel.Controls[itemPanel.Controls.Count - 1];
// The Form is the correct size, no need to resize it:
if (lastElement.Bottom + lastElement.Margin.Bottom == itemPanel.Height) return;
Height = 38 + lastElement.Bottom + lastElement.Margin.Bottom;
}
However, when called within my SizeChange event, this method causes the Form to "flash" between the initial Height and the new Height:
private void MainForm_SizeChanged(object sender, EventArgs e)
{
ResizeForm();
}
I'm guessing the reason is because setting Height will fire the SizeChange event again, but I don't know how to resolve this issue. When I print out the values of lastElement.Bottom + lastElement.Margin.Bottom and itemPanel.Height after setting the Height, they are identical, but the code is still somehow reaching that point.
In a nutshell, I want only the form Width to be manually altered, but the Height of the form to change when items are added or the Width is changed, so that all controls inside the FlowLayoutPanel can be viewed.
However, when called within my SizeChange event, this method causes
the Form to "flash" between the initial Height and the new Height
Basically any of the stock "resize" events for your Form will occur too late for you to change the size without it being noticeable.
You'll want to trap the WM_SIZING message:
Sent to a window that the user is resizing. By processing this
message, an application can monitor the size and position of the drag
rectangle and, if needed, change its size or position.
This will allow you to change the size of the Form before it has actually been updated on the screen.
It would look something like this:
public partial class Form1 : Form
{
private struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
enum HitTest
{
Caption = 2,
Transparent = -1,
Nowhere = 0,
Client = 1,
Left = 10,
Right = 11,
Top = 12,
TopLeft = 13,
TopRight = 14,
Bottom = 15,
BottomLeft = 16,
BottomRight = 17,
Border = 18
}
private const int WM_SIZING = 0x214;
private const int WM_NCHITTEST = 0x84;
public Form1()
{
InitializeComponent();
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCHITTEST:
var result = (HitTest)m.Result.ToInt32();
if (result == HitTest.Top || result == HitTest.Bottom)
m.Result = new IntPtr((int)HitTest.Caption);
if (result == HitTest.TopLeft || result == HitTest.BottomLeft)
m.Result = new IntPtr((int)HitTest.Left);
if (result == HitTest.TopRight || result == HitTest.BottomRight)
m.Result = new IntPtr((int)HitTest.Right);
break;
case WM_SIZING:
// Retrieve the "proposed" size of the Form in "rc":
RECT rc = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
// ... do something with "rc" ...
// this is your code (slightly modified):
if (itemPanel.Controls.Count > 0)
{
var lastElement = itemPanel.Controls[itemPanel.Controls.Count - 1];
if (lastElement.Bottom + lastElement.Margin.Bottom != itemPanel.Height)
{
int Height = 38 + lastElement.Bottom + lastElement.Margin.Bottom;
rc.Bottom = rc.Top + Height; // <--- use "Height" to update the "rc" struct
}
}
// Put the updated "rc" back into message structure:
Marshal.StructureToPtr(rc, m.LParam, true);
break;
}
}
}
Give this a try:
private void ResizeForm()
{
this.SuspendLayout(); // Suspends the layout logic until ResumeLayout() is called (below)
if (itemPanel.Controls.Count < 1) return;
var lastElement = itemPanel.Controls[itemPanel.Controls.Count - 1];
// The Form is the correct size, no need to resize it:
if (lastElement.Bottom + lastElement.Margin.Bottom == itemPanel.Height) return;
Height = 38 + lastElement.Bottom + lastElement.Margin.Bottom;
this.ResumeLayout(); // ADD THIS AS WELL
}
Related
The Windows command console only allows you to resize the window to a multiple of the character size. This "snapping" of the window size is instantaneous and does not flicker. In native code, this is done by processing the WM_SIZING message and modifying the RECT structure accordingly.
In C#, I tried overriding the OnResize method, computing the "snapped" size, and setting the Form's ClientSize property accordingly. Unfortunately, the size keeps jumping between the snapped size and whatever size the cursor currently dictates.
protected override void OnResize(EventArgs e)
{
int tgtCols = (ClientSize.Width + 4) / 8;
int tgtLines = (ClientSize.Height + 8) / 15;
if (cols != tgtCols || lines != tgtLines)
{
cols = tgtCols;
lines = tgtLines;
int tgtWidth = cols * 8;
int tgtHeight = lines * 15;
//ClientSize = new Size(tgtWidth, tgtHeight);
Size = new Size(tgtWidth + exWidth, tgtHeight + exHeight);
}
base.OnResize(e);
}
As you can see, I've tried using both the Size and ClientSize properties, but both yield the same effect. Is there a better way of constraining the size? Or do I need to manually intercept the WM_SIZING message?
EDIT: I also tried manually intercepting WM_SIZING, but I get the same result:
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_SIZING:
DoSizeSnap(ref m);
m.Result = new IntPtr(1);
break;
default:
base.WndProc(ref m);
break;
}
}
private unsafe void DoSizeSnap(ref Message m)
{
int edge = m.WParam.ToInt32();
RECT *pRect = (RECT *)m.LParam.ToPointer();
int tgtCols = (pRect->right - pRect->left - exWidth + 4) / 8;
int tgtLines = (pRect->bottom - pRect->top - exHeight + 8) / 15;
if (cols != tgtCols || lines != tgtLines)
{
cols = tgtCols;
lines = tgtLines;
int tgtWidth = cols * 8;
int tgtHeight = lines * 15;
// TODO: handle edge
pRect->right = pRect->left + tgtWidth + exWidth;
pRect->bottom = pRect->top + tgtHeight + exHeight;
}
}
Subscribing to the Resize event doesn't work either.
The problem is the statement if (cols != tgtCols || lines != tgtLines). This causes the size snapping to occur only when the target lines/columns changes, not when the window width/height changes. This was to prevent infinite recursion, but the Resize event is not fired if the size does not actually change, so the if statement is unnecessary.
I have a winform window. When I change the size of the screen, the screen immediately increases or decreases.
I would prefer the Resize behavior of the window will be like Split Container, as long as I drag the mouse I see only line that marks what will be the window size, and only in leaving the Resize operation will be made.
I saw several examples that show that by hiding the frame of the window, and then by clicking on the window itself paint frame.
I want that by clicking on the frame of the window(I don't want to hide the frame) and not on the window.
Is there any way to do this? (May override the behavior of the Resize in any way).
I'm pretty sure that you can't find any solution on the Internet. However I've tried a demo for this and it works pretty well.
In winforms and many other UI technologies, you can't render something outside the window itself. To get the effect we want, we have to render some indicative border outside or inside the window depending on how user resizes it. So looks like we're stuck?
BUT there is a kind of technique to do that (I call it layer technique). We need a transparent, non-focused layer to render the indicative border. This layer will have its Size and Location synchronized with the Size and Location (with just a little offset) of the main window. The layer will also be invisible by default and only shows when user resizes and hides when ending resizing.
That's pretty OK with the technique I mentioned. However how to prevent/discard the default resizing when user resizes the window? It's luckily that Win32 supports 2 messages for this to be done easily:
WM_RESIZING : is sent to the window when user starts and keeps resizing. The LParam holds the RECT structure of the current window when resizing. We read this info to render the indicative border correctly. Then we need to modify this RECT to the current Bounds of the window to discard the default resizing effect (the size and location are changed immediately).
WM_EXITSIZEMOVE : is sent to the window when the resizing or moving ends. We need to catch this message to assign the Size and Location of the window based on the Size and Location of the transparent layer and of course hide the layer then.
Now the problem is totally solvable. Here is the demo code I've made. Note that there is a very nasty unsolvable and incomprehensible bug here, it happens when you resize the Top-Left corner, the Size is updated correctly after releasing mouse but the Location is set with an offset. I've debugging but no luck. At some point the Top and Left jumps to unexpected values for no clear reason. However, resizing by all the sides (left, top, right, bottom) and other corners is OK. In fact, resizing by the Top-Left corner is hardly done by user so this solution is acceptable, I think.
//Must add using System.Runtime.InteropServices;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Sizing border initialization
SizingBorderWidth = 3;
SizingBorderStyle = DashStyle.Custom;
SizingBorderColor = Color.Orange;
//layer initialization
layer.Owner = this;//especially this one.
layer.Width = Width + SizingBorderWidth * 2;
layer.Height = Height + SizingBorderWidth * 2;
//Paint the border when sizing
layer.Paint += (s, e) => {
using (Pen p = new Pen(SizingBorderColor) { Width = SizingBorderWidth }) {
if (Use3DSizingBorder) {
ControlPaint.DrawBorder3D(e.Graphics, sizingRect.Left, sizingRect.Top, sizingRect.Width, sizingRect.Height, Border3DStyle.Bump, Border3DSide.All);
}
else {
p.DashStyle = SizingBorderStyle;
p.LineJoin = LineJoin.Round;
if(p.DashStyle == DashStyle.Custom)
p.DashPattern = new float[] { 8f, 1f, 1f, 1f };//length of each dash from right to left
e.Graphics.DrawRectangle(p, sizingRect);
}
}
};
//Bind the Location of the main form and the layer form together
LocationChanged += (s, e) => {
Point p = Location;
p.Offset(-SizingBorderWidth, -SizingBorderWidth);
layer.Location = p;
};
//Set the intial Location of layer
Load += (s, e) =>{
Point p = Location;
p.Offset(-SizingBorderWidth, -SizingBorderWidth);
layer.Location = p;
};
}
//Set this to true to use 3D indicative/preview border
public bool Use3DSizingBorder { get; set; }
//Change the indicative/preview border thickness
public int SizingBorderWidth { get; set; }
//Change the indicative/preview border style
public DashStyle SizingBorderStyle { get; set; }
//Change the indicative/preview border color
public Color SizingBorderColor { get; set; }
//hold the current sizing Rectangle
Rectangle sizingRect;
bool startSizing;
bool suppressSizing;
//This is a Win32 RECT struct (don't use Rectangle)
public struct RECT
{
public int left, top, right, bottom;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x214&&!suppressSizing)//WM_SIZING = 0x214
{
RECT rect = (RECT) m.GetLParam(typeof(RECT));
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
sizingRect = new Rectangle() {X = SizingBorderWidth/2, Y = SizingBorderWidth/2,
Width = w, Height = h};
layer.Left = rect.left-SizingBorderWidth;
layer.Top = rect.top-SizingBorderWidth;
layer.Width = w+2*SizingBorderWidth;
layer.Height = h+2*SizingBorderWidth;
if (!startSizing)
{
layer.Show();
startSizing = true;
}
layer.Invalidate();
//Keep the current position and size fixed
rect.right = Right;
rect.bottom = Bottom;
rect.top = Top;
rect.left = Left;
//---------------------------
Marshal.StructureToPtr(rect, m.LParam, true);
}
if (m.Msg == 0x232)//WM_EXITSIZEMOVE = 0x232
{
layer.Visible = false;
BeginInvoke((Action)(() => {
suppressSizing = true;
Left = layer.Left + SizingBorderWidth;
Top = layer.Top + SizingBorderWidth;
Width = layer.Width - 2 * SizingBorderWidth;
Height = layer.Height - SizingBorderWidth * 2;
suppressSizing = false;
}));
startSizing = false;
}
base.WndProc(ref m);
}
//Here is the layer I mentioned before.
NoActivationForm layer = new NoActivationForm();
}
public class NoActivationForm : Form {
public NoActivationForm() {
//The following initialization is very important
TransparencyKey = BackColor;
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = false;
StartPosition = FormStartPosition.Manual;
//----------------------------------------------
}
protected override bool ShowWithoutActivation {
get { return true; }
}
}
Some screen shots:
EDIT: (This edit was suggested by Hodaya Shalom, the OP (weird :)
I found a solution to the left corner problem :
before the BeginInvoke I save the variables and in the invoke I put the local variable:
int _top = layer.Top + SizingBorderWidth;
int _left = layer.Left + SizingBorderWidth;
int _width = layer.Width - 2 * SizingBorderWidth;
int _height = layer.Height - SizingBorderWidth * 2;
BeginInvoke((Action)(() => {
suppressSizing = true;
Left = _left;
Top = _top;
Width =_width;
Height =_height;
suppressSizing = false;
}));
I have implemented a picturebox in my in my form.I even implemented the scrollbars to make the image fit in it.so now the problem is when i try to scroll the button down,it scrolls down and immediately when i leave the mouse the button scrolls up ..here is the code implemnted please give some suggestions..
public void DisplayScrollBars()
{
// If the image is wider than the PictureBox, show the HScrollBar.
if (pictureBox1.Width > pictureBox1.Image.Width - this.vScrollBar1.Width)
{
hScrollBar1.Visible = false;
}
else
{
hScrollBar1.Visible = true;
}
// If the image is taller than the PictureBox, show the VScrollBar.
if (pictureBox1.Height >
pictureBox1.Image.Height - this.hScrollBar1.Height)
{
vScrollBar1.Visible = false;
}
else
{
vScrollBar1.Visible = true;
}
}
private void HandleScroll(Object sender, ScrollEventArgs se)
{
/* Create a graphics object and draw a portion
of the image in the PictureBox. */
Graphics g = pictureBox1.CreateGraphics();
g.DrawImage(pictureBox1.Image,
new Rectangle(0, 0, pictureBox1.Right - vScrollBar1.Width,
pictureBox1.Bottom - hScrollBar1.Height),
new Rectangle(hScrollBar1.Value, vScrollBar1.Value,
pictureBox1.Right - vScrollBar1.Width,
pictureBox1.Bottom - hScrollBar1.Height),
GraphicsUnit.Pixel);
pictureBox1.Update();
}
public void SetScrollBarValues()
{
// Set the Maximum, Minimum, LargeChange and SmallChange properties.
this.vScrollBar1.Minimum = 0;
this.hScrollBar1.Minimum = 0;
// If the offset does not make the Maximum less than zero, set its value.
if ((this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width) > 0)
{
this.hScrollBar1.Maximum =
this.pictureBox1.Image.Size.Width - pictureBox1.ClientSize.Width;
}
// If the VScrollBar is visible, adjust the Maximum of the
// HSCrollBar to account for the width of the VScrollBar.
if (this.vScrollBar1.Visible)
{
this.hScrollBar1.Maximum += this.vScrollBar1.Width;
}
this.hScrollBar1.LargeChange = this.hScrollBar1.Maximum / 10;
this.hScrollBar1.SmallChange = this.hScrollBar1.Maximum / 20;
// Adjust the Maximum value to make the raw Maximum value
// attainable by user interaction.
this.hScrollBar1.Maximum += this.hScrollBar1.LargeChange;
// If the offset does not make the Maximum less than zero, set its value.
if ((this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height) > 0)
{
this.vScrollBar1.Maximum =
this.pictureBox1.Image.Size.Height - pictureBox1.ClientSize.Height;
}
// If the HScrollBar is visible, adjust the Maximum of the
// VSCrollBar to account for the width of the HScrollBar.
if (this.hScrollBar1.Visible)
{
this.vScrollBar1.Maximum += this.hScrollBar1.Height;
}
this.vScrollBar1.LargeChange = this.vScrollBar1.Maximum / 10;
this.vScrollBar1.SmallChange = this.vScrollBar1.Maximum / 20;
// Adjust the Maximum value to make the raw Maximum value
// attainable by user interaction.
this.vScrollBar1.Maximum += this.vScrollBar1.LargeChange;
}
private void pictureBox1_Resize(object sender, EventArgs e)
{
// If the PictureBox has an image, see if it needs
// scrollbars and refresh the image.
if (pictureBox1.Image != null)
{
this.DisplayScrollBars();
this.SetScrollBarValues();
this.Refresh();
}
}
As I comment above, the correct way of doing this is to put your pictureBox in a panel and set the panel.AutoScroll=true. Also you need to set pictureBox.SizeMode=AutoSize so it is sized equal to the size of the image that it contains. Check: PictureBoxSizeMode Enumeration
I have a situation where it would be beneficial to me to allow my windows form to be resized by the user, but only vertically. After some searching, it seems like there isn't much on this particular subject. Is it possible?
You need to set the form's MinimumSize and MaximumSize properties to two sizes with different heights but equal widths.
If you don't want the horizontal resize cursor to appear at all, you'll need to handle the WM_NCHITTEST message, like this:
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
switch (m.Msg) {
case 0x84: //WM_NCHITTEST
var result = (HitTest)m.Result.ToInt32();
if (result == HitTest.Left || result == HitTest.Right)
m.Result = new IntPtr((int)HitTest.Caption);
if (result == HitTest.TopLeft || result == HitTest.TopRight)
m.Result = new IntPtr((int)HitTest.Top);
if (result == HitTest.BottomLeft || result == HitTest.BottomRight)
m.Result = new IntPtr((int)HitTest.Bottom);
break;
}
}
enum HitTest {
Caption = 2,
Transparent = -1,
Nowhere = 0,
Client = 1,
Left = 10,
Right = 11,
Top = 12,
TopLeft = 13,
TopRight = 14,
Bottom = 15,
BottomLeft = 16,
BottomRight = 17,
Border = 18
}
Just an idea...
public partial class Form1 : Form {
int _width;
public Form1() {
_width = this.Width;
InitializeComponent();
}
protected override void OnResize(EventArgs e) {
this.Width = _width;
base.OnResize(e);
}
}
EDIT: please note that the min/max size solutions work much better than this hack :)
Set the max & min size for the width of the form only.
Let the FormBorderStyle to Resizable and set MaximumSize and MinimumSize = new Size(this.Width, 0)
Correction:
this.MinimumSize = new Size(this.Width, 0);
this.MaximumSize = new Size(this.Width, Int32.MaxValue);
Yes, it is possible. Just set your form.MinimumSize.Width = form.MaximumSize.Width = 100 (or whatever width you want).
To avoid the "rubber-banding" effect of #orsogufo's solution:
public Form1()
{
InitializeComponent();
this.MinimumSize = new Size(500, 0);
this.MaximumSize = new Size(500, Screen.AllScreens.Max(s => s.Bounds.Height));
}
It won't correctly adjust its maximum height to accommodate a larger screen if you resize the screen bounds, but for static screen sizes it works great.
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);
}
}