How to show popup box in windows mobile application? - c#

I am developing a windows mobile application in which I want to show popup box containing DataGrid control of showing particular details when user clicks on a button in a form.
I am using ShowDialog() method but it is working.
Can anyone suggest me how to implement this?
Thanks in advance.

If I understand correctly your question, my solution was to create a custom popup class.
public class Popup : Control
{
private class Const
{
public const int Height = 100;
public static Color BarFrameColor = SystemColors.ControlDark;
public static Color BarShadowColor = Color.Black;
public static Color BackColor = SystemColors.Info;
public static Color ForeColor = SystemColors.InfoText;
}
// [ gdi objects ]
private Bitmap m_bmp;
private Pen m_penShadow, m_penFrame;
private Panel panel;
private VScrollBar vScrollBar;
private Label lblText;
private bool scrolling;
public string Text
{
get
{
return lblText.Text;
}
set
{
lblText.Text = value;
}
}
public bool Scrolling
{
get
{
return this.scrolling;
}
set
{
this.scrolling = value;
}
}
public Popup()
{
this.Hide();
this.ForeColor = Const.ForeColor;
this.BackColor = Const.BackColor;
this.Height = Const.Height;
this.panel = new Panel();
this.panel.BackColor = Const.BackColor;
this.panel.Location = new Point(2, 2);
this.vScrollBar = new VScrollBar();
this.vScrollBar.ValueChanged += new EventHandler(vScrollBar_ValueChanged);
this.lblText = new Label();
this.lblText.Location = new Point(0, 0);
this.lblText.Text = "";
this.panel.Controls.Add(lblText);
this.Controls.Add(vScrollBar);
this.Controls.Add(panel);
CreateGdiObjects();
this.Scrolling = false;
}
private void CreateGdiObjects()
{
// [ gdi objects ]
this.m_penShadow = new Pen(Const.BarShadowColor);
this.m_penFrame = new Pen(Const.BarFrameColor);
}
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
// [ calculate layout ]
this.Left = 0;
if (this.Parent != null)
{
this.Width = this.Parent.Width;
this.Top = this.Parent.Height - this.Height;
}
if (this.Scrolling)
{
this.vScrollBar.Size = new Size(12, this.Height - 4);
this.vScrollBar.Location = new Point(this.Width - 2 - this.vScrollBar.Width, 2);
this.panel.Size = new Size(this.Width - 4 - this.vScrollBar.Width, this.Height - 4);
this.vScrollBar.Minimum = this.panel.Top;
this.vScrollBar.Maximum = this.panel.Height;
this.vScrollBar.Visible = true;
this.lblText.Size = new Size(this.panel.Width, this.Height * 3);
}
else
{
this.panel.Size = new Size(this.Width - 4, this.Height - 4);
this.vScrollBar.Visible = false;
this.lblText.Size = this.panel.Size;
}
this.BringToFront();
}
protected override void OnPaint(PaintEventArgs e)
{
// [ draw progress on memory bitmap ]
CreateMemoryBitmap();
Graphics g = Graphics.FromImage(this.m_bmp);
DrawControl(g);
// [ blit to screen ]
e.Graphics.DrawImage(this.m_bmp, 0, 0);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// [ don't pass to base since we paint everything, avoid flashing ]
}
private void CreateMemoryBitmap()
{
// [ see if need to create bitmap ]
if (this.m_bmp == null || this.m_bmp.Width != this.Width || this.m_bmp.Height != this.Height)
this.m_bmp = new Bitmap(this.Width, this.Height);
}
private void DrawControl(Graphics g)
{
g.Clear(this.BackColor);
Rectangle rc = new Rectangle(0, 0, this.Width - 1, this.Height - 1);
g.DrawRectangle(this.m_penShadow, rc);
rc.Inflate(-1, -1);
g.DrawRectangle(this.m_penFrame, rc);
}
private void vScrollBar_ValueChanged(object sender, System.EventArgs e)
{
this.lblText.Top = -this.vScrollBar.Value;
}
}

Related

Resize rectangle with form Size in real time?

Here is the following rectangle below:
When I resize the form, I need this rectangle to match the size of the form.
When changing the width of the rectangle, do not interfere with its visibility within the form.
I'm using the following:
Note:
I did the rectangle manually, but if you have rectangle ready, better yet!
public Form1()
{
InitializeComponent();
this.Paint += Form1_Paint;
this.rectangles = new Dictionary<string, Rectangle>();
this.sizeScreen = this.Size;
this.sizeRectangles = new Size(8, 8);
this.brush = new SolidBrush(Color.Red);
FillLeft();
FillRight();
FillUp();
FillDown();
}
private Size sizeScreen;
private Size sizeRectangles;
private SolidBrush brush;
private Dictionary<string, Rectangle> rectangles;
private void FillLeft()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeScreen.Height,
Width = this.sizeRectangles.Width,
X = 0,
Y = this.sizeRectangles.Height
};
this.rectangles.Add("left", rectangle);
}
private void FillRight()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeScreen.Height,
Width = this.sizeRectangles.Width,
X = this.sizeScreen.Width - (this.sizeRectangles.Width * 5),
Y = this.sizeRectangles.Height
};
this.rectangles.Add("right", rectangle);
}
private void FillUp()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeRectangles.Height,
Width = this.sizeScreen.Width,
X = 0,
Y = this.sizeRectangles.Height
};
this.rectangles.Add("up", rectangle);
}
private void FillDown()
{
Rectangle rectangle = new Rectangle()
{
Height = this.sizeRectangles.Height,
Width = this.sizeScreen.Width,
X = 0,
Y = this.sizeScreen.Height - (this.sizeRectangles.Height * 11)
};
this.rectangles.Add("down", rectangle);
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
for (int i = 0; i < this.rectangles.Count; i++)
{
e.Graphics.FillRectangles(this.brush, this.rectangles.Values.ToArray());
}
}
I want to set the rectangle on the form when it is resized
This is the way I'm creating the rectangle, but it does not stay right on the screen, to resize it I do not know
I think this would simplify what you are trying to do:
const int PenWidth = 10;
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = this.ClientRectangle;
Pen pen = new Pen(Color.Red, PenWidth);
e.Graphics.DrawRectangle(pen, r);
}
You could even add a margin:
const int PenWidth = 10;
const int PenMargin = 10;
private void Form1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = this.ClientRectangle;
r.Inflate(-PenMargin, -PenMargin);
Pen pen = new Pen(Color.Red, PenWidth);
e.Graphics.DrawRectangle(pen, r);
}
To prevent traces (suggested by Wyck):
private void Form1_Resize(object sender, EventArgs e)
{
Invalidate();
}
Handle the Resize event and call Invalidate in the handler. Create a Pen of the desired color and width and set its Alignment to Inset. Handle the Paint event and in the handler call DrawRectangle passing in the ClientRectangle of the form.
Here is an example.
const float borderWidth = 8.0f;
Pen borderPen = new Pen(Color.Red, borderWidth) { Alignment = System.Drawing.Drawing2D.PenAlignment.Inset };
public Form2()
{
InitializeComponent();
this.Paint += Form2_Paint;
this.Resize += Form2_Resize;
}
private void Form2_Resize(object sender, EventArgs e)
{
Invalidate();
}
private void Form2_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(borderPen, this.ClientRectangle);
}
Apply the following fixes to the code:
Set ResizeRedraw property of the form to true. It sets the underlying style for the form so by each resize it sends the paint message and you don't need to handle Resize event.
Use DrawRectangle and draw using wide pen. So you don't need to fill multiple rectangles.
Set the PenAlignment to Inset. So you don't need to calculate the location of rectangle.
Do dispose the pen when you don't need it.
Example
public Form1()
{
InitializeComponent();
ResizeRedraw = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (var pen = new Pen(Color.Red, PenWidth))
{
pen.Alignment = System.Drawing.Drawing2D.PenAlignment.Inset;
e.Graphics.DrawRectangle(pen, ClientRectangle);
}
}
i have used this on my current project. when ever you resize the form, it will automatically resize all the object inside your form
i have class named clsResize and i call this on the form load.
1st you have to initialize the class inside the form then create 2 new method.
see example below
public partial class frmNewForm : Form
{
clsResize _form_resize;
public string selectedProd;
public frmNewForm()
{
InitializeComponent();
_form_resize = new clsResize(this);
this.Load += _Load;
this.Resize += _Resize;
}
private void _Load(object sender, EventArgs e)
{
_form_resize._get_initial_size();
}
private void _Resize(object sender, EventArgs e)
{
_form_resize._resize();
}
}
and here is the class that i used.
public class clsResize
{
List<System.Drawing.Rectangle> _arr_control_storage = new List<System.Drawing.Rectangle>();
private bool showRowHeader = false;
public clsResize(Form _form_)
{
form = _form_; //the calling form
_formSize = _form_.ClientSize; //Save initial form size
_fontsize = _form_.Font.Size; //Font size
}
private float _fontsize { get; set; }
private System.Drawing.SizeF _formSize {get;set; }
private Form form { get; set; }
public void _get_initial_size() //get initial size//
{
var _controls = _get_all_controls(form);//call the enumerator
foreach (Control control in _controls) //Loop through the controls
{
_arr_control_storage.Add(control.Bounds); //saves control bounds/dimension
//If you have datagridview
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
}
}
public void _resize() //Set the resize
{
double _form_ratio_width = (double)form.ClientSize.Width /(double)_formSize.Width; //ratio could be greater or less than 1
double _form_ratio_height = (double)form.ClientSize.Height / (double)_formSize.Height; // this one too
var _controls = _get_all_controls(form); //reenumerate the control collection
int _pos = -1;//do not change this value unless you know what you are doing
try
{
foreach (Control control in _controls)
{
// do some math calc
_pos += 1;//increment by 1;
System.Drawing.Size _controlSize = new System.Drawing.Size((int)(_arr_control_storage[_pos].Width * _form_ratio_width),
(int)(_arr_control_storage[_pos].Height * _form_ratio_height)); //use for sizing
System.Drawing.Point _controlposition = new System.Drawing.Point((int)
(_arr_control_storage[_pos].X * _form_ratio_width), (int)(_arr_control_storage[_pos].Y * _form_ratio_height));//use for location
//set bounds
control.Bounds = new System.Drawing.Rectangle(_controlposition, _controlSize); //Put together
//Assuming you have a datagridview inside a form()
//if you want to show the row header, replace the false statement of
//showRowHeader on top/public declaration to true;
if (control.GetType() == typeof(DataGridView))
_dgv_Column_Adjust(((DataGridView)control), showRowHeader);
//Font AutoSize
control.Font = new System.Drawing.Font(form.Font.FontFamily,
(float)(((Convert.ToDouble(_fontsize) * _form_ratio_width) / 2) +
((Convert.ToDouble(_fontsize) * _form_ratio_height) / 2)));
}
}
catch(Exception e)
{
MessageBox.Show(e.Message);
return;
}
}
private void _dgv_Column_Adjust(DataGridView dgv, bool _showRowHeader) //if you have Datagridview
//and want to resize the column base on its dimension.
{
int intRowHeader = 0;
const int Hscrollbarwidth = 5;
if (_showRowHeader)
intRowHeader = dgv.RowHeadersWidth;
else
dgv.RowHeadersVisible = false;
for (int i = 0; i < dgv.ColumnCount; i++)
{
if (dgv.Dock == DockStyle.Fill) //in case the datagridview is docked
dgv.Columns[i].Width = ((dgv.Width - intRowHeader) / dgv.ColumnCount);
else
dgv.Columns[i].Width = ((dgv.Width - intRowHeader - Hscrollbarwidth) / dgv.ColumnCount);
}
}
private static IEnumerable<Control> _get_all_controls(Control c)
{
return c.Controls.Cast<Control>().SelectMany(item =>
_get_all_controls(item)).Concat(c.Controls.Cast<Control>()).Where(control =>
control.Name != string.Empty);
}
}

C# Graphics Object is currently in use elsewhere

I created a game based on a totorial to start learning, I am rendering my game with renderScreen(), when I moved my window on screen I have got this exception "Object is currently in use elsewhere". I know the reason of error but I could not fix it as I do not know how to do that.
What can I do ? Forgive me if question is stupid.
engine.cs
//MEMBERS
public static Graphics drawHandle;
private Thread renderThread;
public engine(Graphics g)
{
drawHandle = g;
}
private object bufferLock = new object();
public void init()
{
renderThread = new Thread(new ThreadStart(renderScreen));
renderThread.Start();
}
public void stop()
{
renderThread.Abort();
}
public static Bitmap frame = new Bitmap(Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);
Rectangle rect = new Rectangle(0, 0, frame.Width, frame.Height);
private void renderScreen()
{
int framesRendered = 0;
long startTime = Environment.TickCount;
Graphics frameGraphics = Graphics.FromImage(frame);
Unit1 unit1 = new Unit1("test1");
Unit1 unit2 = new Unit1("test2");unit2.x = 250; unit2.y = 100;
Globals.GameUnitsList.Add(unit1); Globals.GameUnitsList.Add(unit2);
while (true)
{
//BACKGROUND
frameGraphics.FillRectangle(new SolidBrush(Color.DarkBlue),0,0, Globals.CANVAS_WIDTH, Globals.CANVAS_HEIGHT);
//BOXES
Rectangle rect = new Rectangle(unit1.x, unit1.y, 50, 50);
unit1.rectangle = rect;
unit1.fillColor = Brushes.LightBlue;
unit1.hitPoints = 100;
unit1.Health = 10;
frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);
frameGraphics.FillRectangle(unit1.fillColor, unit1.rectangle);
Rectangle rect2 = new Rectangle(unit2.x, unit2.y, 50, 50);
unit2.rectangle = rect2;
unit2.fillColor = Brushes.LightBlue;
unit2.hitPoints = 100;
unit2.Health = 50;
frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);
frameGraphics.FillRectangle(unit2.fillColor, unit2.rectangle);
//HEALTH BAR
HealthBar hb = new HealthBar();
hb.barColor = Brushes.YellowGreen;
hb.damageColor = Brushes.Red;
frameGraphics.FillRectangle(hb.damageColor, hb.Draw(unit1, unit1.x, unit1.y)[1]);
frameGraphics.FillRectangle(hb.barColor, hb.Draw(unit1, unit1.x, unit1.y)[0]);
HealthBar hb2 = new HealthBar();
hb2.barColor = Brushes.YellowGreen;
hb2.damageColor = Brushes.Red;
frameGraphics.FillRectangle(hb2.damageColor, hb2.Draw(unit2, unit2.x, unit2.y)[1]);
frameGraphics.FillRectangle(hb2.barColor, hb2.Draw(unit2, unit2.x, unit2.y)[0]);
//UNIT NAMES
frameGraphics.DrawString(unit1.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit1.x + 50, unit1.y + 50);
frameGraphics.DrawString(unit2.unitName, new Font("Arial", 24, FontStyle.Bold), Brushes.Yellow, unit2.x + 50, unit2.y + 50);
drawHandle.DrawImage(frame, 0, 0);
//BENCHMARKING
if (Environment.TickCount >= startTime + 750)
{
framesRendered++;
}
if (Environment.TickCount>=startTime+1000)
{
Console.WriteLine("Gomi-Invade Plan Game:"+framesRendered +"fps "+ Environment.TickCount);
framesRendered = 0;
startTime = Environment.TickCount;
}
}
}
gamewindow.cs
...
public static GameWindow gameW;
Game game = new Game();
...
//I have this code inside it but is this wrong ?
private void canvas_Paint(object sender, PaintEventArgs e)
{
Graphics g = canvas.CreateGraphics();
game.startGraphics(g);
}
...
game.cs
private engine Gengine;
public void startGraphics(Graphics g)
{
Gengine = new GomiEngine(g);
Gengine.init();
}
public void stopGame()
{
Gengine.stop();
}
You cannot render screen in your own thread, you need to call invalidate in invoke which will enqueue windows message to windows message loop which will be processed on main thread.
private void DoWorkInThread(object sender, EventArgs e)
{
while (true)
{
lock(this)
{
//update member properties
}
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate void ()
{
//this.Invalidate(); //if you don't need to render every frame, invalidate is better then refresh
this.Refresh(); //call refresh for immediate update
});
}
}
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
lock(this)
{
//read your member which are modifies by the thread
}
//do rendering
e.Graphics.Draw(...);
}

ContainerControl Won't Draw Controls On Scroll Properly

I have a custom CheckListBox control that is supposed to function the same way as the CheckedListBox control but it is not. The problem is when I scroll down, the drawing gets all messed up. The container won't actually scroll down, it will just "jitter" the check boxes around, draw random lines, etc.
Update: I changed the code so the location of each CheckBox was set in the OnControlAdded method instead of the OnPaint method. It now scrolls fine, but the drawing is still messed up! The border is missing, the BackColor changes, the lines for the check boxes are not straight; just a whole mess of things. It works perfectly in the designer (the scrolling and drawing), but not when I run the program.
Here's the code for the control:
public class ChromeCheckListBox : ChromeContainerControl
{
[Description("Determines what corner(s) will be rounded.")]
public Utilities.RoundedRectangle.RectangleCorners Corners { get; set; }
private int cornerRadius;
[Description("Determines the radius of the the corners")]
public int CornerRadius
{
get { return cornerRadius; }
set
{
if (value < 1)
Utilities.ThrowError("The radius cannot be less than 1. If you want no radius, set Corners to None.");
else
cornerRadius = value;
}
}
[Description("Determines the list of ChromeRadioButton controls that are displayed.")]
private ChromeCheckBox[] items;
public ChromeCheckBox[] Items
{
get { return items; }
set
{
items = value;
Controls.Clear();
Controls.AddRange(items);
}
}
public ChromeCheckListBox()
{
this.AutoScroll = true;
this.Corners = Utilities.RoundedRectangle.RectangleCorners.All;
this.CornerRadius = 1;
this.Items = new ChromeCheckBox[0];
this.Size = new Size(100, 100);
}
protected override void OnControlAdded(ControlEventArgs e)
{
for (int i = 0; i < Items.Length; i++)
{
if (i == 0)
Items[i].Location = new Point(2 + Padding.Left, 2 + Padding.Top);
else
Items[i].Location = new Point(2 + Padding.Left, Items[i - 1].Location.Y + Size.Ceiling(this.CreateGraphics().MeasureString(Items[i - 1].Text, Items[i - 1].Font)).Height);
}
base.OnControlAdded(e);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics canvas = e.Graphics;
canvas.SmoothingMode = SmoothingMode.HighQuality;
Rectangle region = new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
GraphicsPath path = Utilities.RoundedRectangle.Create(region, CornerRadius, Corners);
canvas.FillPath(new LinearGradientBrush(region, fillColors[0], fillColors[1], 90), path);
canvas.DrawPath(new Pen(borderColor), path);
}
}
I got it! Instead of setting the location of the check boxes in the OnPaint method, I should set them in the OnControlAdded method. Also, on the OnScroll method, I need to Invalidate the control causing it to redraw.
So, it should (well maybe not should, but could) look like this:
public class ChromeCheckListBox : ChromeContainerControl
{
[Description("Determines what corner(s) will be rounded.")]
public Utilities.RoundedRectangle.RectangleCorners Corners { get; set; }
private int cornerRadius;
[Description("Determines the radius of the the corners")]
public int CornerRadius
{
get { return cornerRadius; }
set
{
if (value < 1)
Utilities.ThrowError("The radius cannot be less than 1. If you want no radius, set Corners to None.");
else
cornerRadius = value;
}
}
[Description("Determines the list of ChromeRadioButton controls that are displayed.")]
private ChromeCheckBox[] items;
public ChromeCheckBox[] Items
{
get { return items; }
set
{
items = value;
Controls.Clear();
Controls.AddRange(items);
}
}
public ChromeCheckListBox()
{
this.AutoScroll = true;
this.Corners = Utilities.RoundedRectangle.RectangleCorners.All;
this.CornerRadius = 1;
this.Items = new ChromeCheckBox[0];
this.Size = new Size(100, 100);
}
protected override void OnControlAdded(ControlEventArgs e)
{
for (int i = 0; i < Items.Length; i++)
{
if (i == 0)
Items[i].Location = new Point(2 + Padding.Left, 2 + Padding.Top);
else
Items[i].Location = new Point(2 + Padding.Left, Items[i - 1].Location.Y + Size.Ceiling(this.CreateGraphics().MeasureString(Items[i - 1].Text, Items[i - 1].Font)).Height);
}
base.OnControlAdded(e);
}
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
base.Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics canvas = e.Graphics;
canvas.SmoothingMode = SmoothingMode.AntiAlias;
Rectangle region = new Rectangle(0, 0, ClientRectangle.Width - 1, ClientRectangle.Height - 1);
GraphicsPath path = Utilities.RoundedRectangle.Create(region, CornerRadius, Corners);
canvas.FillPath(new LinearGradientBrush(region, fillColors[0], fillColors[1], 90), path);
canvas.DrawPath(new Pen(borderColor), path);
}

Windows form combobox custom form color

I have been playing around with customizing the WinForm combobox...So far I have the following:
Using this code:
public class ComboBoxWithBorder : ComboBox
{
private Color _borderColor = Color.Black;
private ButtonBorderStyle _borderStyle = ButtonBorderStyle.Solid;
private static int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT)
{
Graphics g = Graphics.FromHwnd(Handle);
Rectangle bounds = new Rectangle(0, 0, Width, Height);
ControlPaint.DrawBorder(g, bounds, _borderColor, _borderStyle);
}
}
[Category("Appearance")]
public Color BorderColor
{
get { return _borderColor; }
set
{
_borderColor = value;
Invalidate(); // causes control to be redrawn
}
}
[Category("Appearance")]
public ButtonBorderStyle BorderStyle
{
get { return _borderStyle; }
set
{
_borderStyle = value;
Invalidate();
}
}
}
However, I am trying to achieve something similar to this:
Is it possible to change the background color of the white dropdown box to a darker color?
Is it possible to change the dropdown list border from white to a different color?
Try This Class
Refer
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
public class FlatCombo : ComboBox
{
private Brush BorderBrush = new SolidBrush(SystemColors.Window);
private Brush ArrowBrush = new SolidBrush(SystemColors.ControlText);
private Brush DropButtonBrush = new SolidBrush(SystemColors.Control);
private Color _ButtonColor = SystemColors.Control;
public Color ButtonColor {
get { return _ButtonColor; }
set {
_ButtonColor = value;
DropButtonBrush = new SolidBrush(this.ButtonColor);
this.Invalidate();
}
}
protected override void WndProc(ref Message m)
{
base.WndProc(m);
switch (m.Msg) {
case 0xf:
//Paint the background. Only the borders
//will show up because the edit
//box will be overlayed
Graphics g = this.CreateGraphics;
Pen p = new Pen(Color.White, 2);
g.FillRectangle(BorderBrush, this.ClientRectangle);
//Draw the background of the dropdown button
Rectangle rect = new Rectangle(this.Width - 15, 3, 12, this.Height - 6);
g.FillRectangle(DropButtonBrush, rect);
//Create the path for the arrow
Drawing2D.GraphicsPath pth = new Drawing2D.GraphicsPath();
PointF TopLeft = new PointF(this.Width - 13, (this.Height - 5) / 2);
PointF TopRight = new PointF(this.Width - 6, (this.Height - 5) / 2);
PointF Bottom = new PointF(this.Width - 9, (this.Height + 2) / 2);
pth.AddLine(TopLeft, TopRight);
pth.AddLine(TopRight, Bottom);
g.SmoothingMode = Drawing2D.SmoothingMode.HighQuality;
//Determine the arrow's color.
if (this.DroppedDown) {
ArrowBrush = new SolidBrush(SystemColors.HighlightText);
} else {
ArrowBrush = new SolidBrush(SystemColors.ControlText);
}
//Draw the arrow
g.FillPath(ArrowBrush, pth);
break;
default:
break; // TODO: might not be correct. Was : Exit Select
break;
}
}
//Override mouse and focus events to draw
//proper borders. Basically, set the color and Invalidate(),
//In general, Invalidate causes a control to redraw itself.
#region "Mouse and focus Overrides"
protected override void OnMouseEnter(System.EventArgs e)
{
base.OnMouseEnter(e);
BorderBrush = new SolidBrush(SystemColors.Highlight);
this.Invalidate();
}
protected override void OnMouseLeave(System.EventArgs e)
{
base.OnMouseLeave(e);
if (this.Focused)
return;
BorderBrush = new SolidBrush(SystemColors.Window);
this.Invalidate();
}
protected override void OnLostFocus(System.EventArgs e)
{
base.OnLostFocus(e);
BorderBrush = new SolidBrush(SystemColors.Window);
this.Invalidate();
}
protected override void OnGotFocus(System.EventArgs e)
{
base.OnGotFocus(e);
BorderBrush = new SolidBrush(SystemColors.Highlight);
this.Invalidate();
}
protected override void OnMouseHover(System.EventArgs e)
{
base.OnMouseHover(e);
BorderBrush = new SolidBrush(SystemColors.Highlight);
this.Invalidate();
}
#endregion
}

C# vertical label in a Windows Forms

Is it possible to display a label vertically in a Windows Forms?
Labels are easy, all you have to do is override the Paint event and draw the text vertically. Do note that GDI is optimised for Drawing text horizontally. If you rotate text (even if you rotate through multiples of 90 degrees) it will looks notably worse.
Perhaps the best thing to do is draw your text (or get a label to draw itself) onto a bitmap, then display the bitmap rotated.
Some C# code for drawing a Custom Control with vertical text. Note that ClearType text NEVER works if the text is not horizontal:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
public partial class VerticalLabel : UserControl
{
public VerticalLabel()
{
InitializeComponent();
}
private void VerticalLabel_SizeChanged(object sender, EventArgs e)
{
GenerateTexture();
}
private void GenerateTexture()
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
format.Trimming = StringTrimming.EllipsisCharacter;
Bitmap img = new Bitmap(this.Height, this.Width);
Graphics G = Graphics.FromImage(img);
G.Clear(this.BackColor);
SolidBrush brush_text = new SolidBrush(this.ForeColor);
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
G.DrawString(this.Name, this.Font, brush_text, new Rectangle(0, 0, img.Width, img.Height), format);
brush_text.Dispose();
img.RotateFlip(RotateFlipType.Rotate270FlipNone);
this.BackgroundImage = img;
}
}
Create a class myLabel which can rotate it's Text on any angle specified by you.
You can use it by code or simply dragging from ToolBox
using System.Drawing;
class myLabel:System.Windows.Forms.Label
{
public int RotateAngle { get; set; } // to rotate your text
public string NewText { get; set; } // to draw text
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Brush b =new SolidBrush(this.ForeColor);
e.Graphics.TranslateTransform(this.Width / 2, this.Height / 2);
e.Graphics.RotateTransform(this.RotateAngle);
e.Graphics.DrawString(this.NewText, this.Font,b , 0f, 0f);
base.OnPaint(e);
}
}
Now this custom control is used into your form.
You have to set below properties
1. mylbl.Text = ""; //which can be changed by NewText property
2. mylbl.AutoSize = false; // adjust according to your text
3. mylbl.NewText = "Hello"; // whatever you want to display
4. mylbl.ForeColor = Color.Red; // color to display
5. mylbl.RotateAngle = -90; //angle to rotate
I expanded on Javed Akram's answer to resize the widget automatically (I needed this feature). It works for both positive and negative angles, the way that Javed states:
1. mylbl.Text = ""; // which can be changed by NewText property
2. mylbl.AutoSize = false; // adjust according to your text
3. mylbl.NewText = "Hello"; // whatever you want to display
4. mylbl.ForeColor = Color.Red; // color to display
5. mylbl.RotateAngle = -90; // angle to rotate
Here is the code:
public class RotatingLabel : System.Windows.Forms.Label
{
private int m_RotateAngle = 0;
private string m_NewText = string.Empty;
public int RotateAngle { get { return m_RotateAngle; } set { m_RotateAngle = value; Invalidate(); } }
public string NewText { get { return m_NewText; } set { m_NewText = value; Invalidate(); } }
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Func<double, double> DegToRad = (angle) => Math.PI * angle / 180.0;
Brush b = new SolidBrush(this.ForeColor);
SizeF size = e.Graphics.MeasureString(this.NewText, this.Font, this.Parent.Width);
int normalAngle = ((RotateAngle % 360) + 360) % 360;
double normaleRads = DegToRad(normalAngle);
int hSinTheta = (int)Math.Ceiling((size.Height * Math.Sin(normaleRads)));
int wCosTheta = (int)Math.Ceiling((size.Width * Math.Cos(normaleRads)));
int wSinTheta = (int)Math.Ceiling((size.Width * Math.Sin(normaleRads)));
int hCosTheta = (int)Math.Ceiling((size.Height * Math.Cos(normaleRads)));
int rotatedWidth = Math.Abs(hSinTheta) + Math.Abs(wCosTheta);
int rotatedHeight = Math.Abs(wSinTheta) + Math.Abs(hCosTheta);
this.Width = rotatedWidth;
this.Height = rotatedHeight;
int numQuadrants =
(normalAngle >= 0 && normalAngle < 90) ? 1 :
(normalAngle >= 90 && normalAngle < 180) ? 2 :
(normalAngle >= 180 && normalAngle < 270) ? 3 :
(normalAngle >= 270 && normalAngle < 360) ? 4 :
0;
int horizShift = 0;
int vertShift = 0;
if (numQuadrants == 1)
{
horizShift = Math.Abs(hSinTheta);
}
else if (numQuadrants == 2)
{
horizShift = rotatedWidth;
vertShift = Math.Abs(hCosTheta);
}
else if (numQuadrants == 3)
{
horizShift = Math.Abs(wCosTheta);
vertShift = rotatedHeight;
}
else if (numQuadrants == 4)
{
vertShift = Math.Abs(wSinTheta);
}
e.Graphics.TranslateTransform(horizShift, vertShift);
e.Graphics.RotateTransform(this.RotateAngle);
e.Graphics.DrawString(this.NewText, this.Font, b, 0f, 0f);
base.OnPaint(e);
}
}
I found a way to simply do it without adding code or classes to your project!
When you create your label, simply add:
this.label1.text = "V\nE\nR\nT\nI\nC\nA\nL\n";
This worked for me!
You can rotate text instead of the label control in the OnPaint event or Paint method:
private void uc1_Paint(object sender, PaintEventArgs e)
{
string Name;
var g = e.Graphics;
g.DrawString(Name, new Font("Tahoma", 8), Brushes.Black, 0, 0,
new StringFormat(StringFormatFlags.DirectionVertical));
}
2015 update on an old post. Since most of the other answers seem to heavily affect VS2013's designer in terms of usability, I'd suggest this solution:
http://www.codeproject.com/Articles/19774/Extended-Vertical-Label-Control-in-C-NET
It absolutely works. I found it on net and little changed
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.ComponentModel;
public class VerticalLabel : System.Windows.Forms.Label
{
private bool bFlip = true;
public VerticalLabel()
{
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
StringFormat stringFormat = new StringFormat();
stringFormat.Alignment = StringAlignment.Center;
stringFormat.Trimming = StringTrimming.None;
stringFormat.FormatFlags = StringFormatFlags.DirectionVertical;
Brush textBrush = new SolidBrush(this.ForeColor);
Matrix storedState = g.Transform;
if (bFlip)
{
g.RotateTransform(180f);
g.TranslateTransform(-ClientRectangle.Width,-ClientRectangle.Height);
}
g.DrawString(
this.Text,
this.Font,
textBrush,
ClientRectangle,
stringFormat);
g.Transform = storedState;
}
[Description("When this parameter is true the VLabel flips at 180 degrees."),Category("Appearance")]
public bool Flip180
{
get
{
return bFlip;
}
set
{
bFlip = value;
this.Invalidate();
}
}
}
Used pieces from others
Jeremy
public partial class VerticalLabel_UserControl : UserControl
{
private IComponentChangeService _changeService;
private string strPropertyText = "Vertical Text";
public VerticalLabel_UserControl()
{
InitializeComponent();
}
[EditorBrowsable(EditorBrowsableState.Always)]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Bindable(true)]
public override string Text { get { return base.Text; } set { base.Text = value; this.Invalidate(); } }
private void VerticalLabel_UserControl_SizeChanged(object sender, EventArgs e)
{
GenerateTexture();
}
protected override void OnTextChanged(EventArgs e)
{
base.OnTextChanged(e);
}
private void GenerateTexture()
{
StringFormat format = new StringFormat();
format.Alignment = StringAlignment.Center;
format.LineAlignment = StringAlignment.Center;
// format.Trimming = StringTrimming.EllipsisCharacter;
Bitmap img = new Bitmap(this.Height, this.Width);
Graphics G = Graphics.FromImage(img);
G.Clear(this.BackColor);
SolidBrush brush_text = new SolidBrush(this.ForeColor);
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
G.DrawString(this.strPropertyText, this.Font, brush_text, new Rectangle(0, 0, img.Width, img.Height), format);
img.RotateFlip(RotateFlipType.Rotate270FlipNone);
this.BackgroundImage = img;
brush_text.Dispose();
}
public override System.ComponentModel.ISite Site
{
get
{
return base.Site;
}
set
{
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged -= new ComponentChangedEventHandler(OnComponentChanged);
base.Site = value;
if (!DesignMode)
return;
_changeService = (IComponentChangeService)GetService(typeof(IComponentChangeService));
if (_changeService != null)
_changeService.ComponentChanged += new ComponentChangedEventHandler(OnComponentChanged);
}
}
private void OnComponentChanged(object sender, ComponentChangedEventArgs ce)
{
VerticalLabel_UserControl label = ce.Component as VerticalLabel_UserControl;
if (label == null || !label.DesignMode)
return;
if (((IComponent)ce.Component).Site == null || ce.Member == null || ce.Member.Name != "Text")
return;
//Causes the default text to be updated
string strName = this.Name.ToLower();
string strText = this.Text.ToLower();
if (strText.Contains(strName))
{
this.Text = "Vertical Text";
}
else
{
strPropertyText = this.Text;
}
//Prints the text vertically
GenerateTexture();
}
}
I just turned off the AutoSize property and resized the label vertically. I made the label wide enough for only one character. Then I changed TextAlign to center to make the alignment look better. This worked great for me.

Categories

Resources