Custom control rendering weird in Tapcontrol - c#

Here is an odd one and it will be a bit long to describe so bear with me on this one.
I have a control made for c# 4 client profile called Toggleswitch (tsw). This toggleswitch is design to act like the metro switch, and that is does splendidly ... until it is added to a Tap control/Tap page then :
the rendering acts all weird not drawing the background properly and the on/off label don’t show up. This affects other controls as well, it like the Whole form won't draw.
also both VS 2010 and 2013 design editors properties fields freeze up so I can't access the other controls
and if left in normal the program won't build ... basically crashed VS..
BUT, if I change the tap control from normal to either flatbutton or button then it stops and runs smoothly as always and that is fine, but then I started wondering why it don't render in the normal
So here is what I have tried
the tsw extends Buttonbase for clickability. So I changed that to control then the OnPaint gets called in a unlimited loop so that don’t help, also the click don’t Work but that is less important right now
I extended of button, no help there still weird
override every single method from both button and buttonbase to see if that helped still nothing.
After looking at the forms designer I found that the only property the gets changed is the UseVisualStyleBackColor when false it works when true it don't, so I made an override that forces it to be false, still doesn't work :/
I even tried to remove the partial keyword.
I spend half a day reading about the defriend methods of both tap and button controls
even found a custom control test the extended of button that worked fine, but there was no reason for it because the only different from what I could see was an if statement in the OnPaint about some rendering.
.... Nothing works ....
Here is the togglewitch in its entirety:
public partial class ToggleSwith : ButtonBase
{
object _Lock = new object();
private Color _OffColor = SystemColors.ControlDarkDark;
private Color _OnColor = Color.LimeGreen;
private bool _ColorText = false;
// private bool _BeenDrawn = false;
private bool _Checked = false;
[Browsable(false)]
public override string Text { get { return null; } }
[Browsable(false)]
public override bool AutoSize{get{return false;}}
[Browsable(false)]
public override ContentAlignment TextAlign { get { return ContentAlignment.MiddleLeft; } }
[Category("Appearance")]
public virtual Color OffColor { get { return _OffColor; } set { _OffColor = value; Invalidate(); } }
[Category("Appearance")]
public virtual Color OnColor { get { return _OnColor; } set { _OnColor = value; Invalidate(); } }
[Category("Appearance")]
public virtual bool ColorText { get { return _ColorText; } set { _ColorText = value; Invalidate(); } }
[Category("Appearance")]
public virtual bool Checked { get { return _Checked; } set { _Checked = value; Invalidate(); } }
new public bool UseVisualStyleBackColor { get { return false; } set{} }
protected override Size DefaultSize { get { return new Size(80, 18); } }
protected override Size DefaultMinimumSize { get { return new Size(40, 13); } }
public event EventHandler ToggleChanged;
public ToggleSwith()
{
this.Size = new Size(80, 18);
InitializeComponent();
this.Click += ToggleSwith_Click;
}
void ToggleSwith_Click(object sender, EventArgs e)
{
lock (_Lock)
{
if (_Checked) _Checked = false;
else _Checked = true;
}
OnToggleChanged();
}
private void OnToggleChanged()
{
if (ToggleChanged != null)
{
EventArgs ea = new EventArgs();
ToggleChanged(this, ea);
}
}
protected override void OnPaint(PaintEventArgs e)
{
this.Controls.Clear();
int toggleblocsize=(int)this.Size.Width/8;
int indent = 23;
int labelx = 2;
// Declare and instantiate a new pen.
SolidBrush OffPen = new SolidBrush(this.OffColor);
SolidBrush OnPen = new SolidBrush(this.OnColor);
SolidBrush BackgroundPen = new SolidBrush(this.BackColor);
SolidBrush BlackPen = new SolidBrush(SystemColors.ControlText);
Pen ControlDarkPen = new Pen(SystemColors.ControlDark);
Pen ControlPen = new Pen(SystemColors.Control);
e.Graphics.FillRectangle(BackgroundPen,0, 0, this.Size.Width,this.Size.Height);
e.Graphics.DrawRectangle(ControlDarkPen, indent, -0, this.Size.Width - (indent+1), this.Size.Height-1);
Label l = new Label();
l.Font = this.Font;
l.Size = new Size((indent-labelx),this.Size.Height);
// if(this.Size.Height <13)l.Location= new Point(labelx,-1);
// else l.Location = new Point(labelx, 0);
l.TextAlign = TextAlign;
l.ForeColor = this.ForeColor;
if (this._Checked)
{
//ligth
e.Graphics.FillRectangle(OnPen, (indent + 2), 2, this.Size.Width - (indent + 4), this.Size.Height - 4);
//Toggle
e.Graphics.DrawRectangle(ControlPen, this.Size.Width - (toggleblocsize+1), -0, this.Size.Width - (indent + 1), this.Size.Height - 1);
e.Graphics.FillRectangle(BlackPen, this.Size.Width - (toggleblocsize), -1, this.Size.Width, this.Size.Height + 1);
if (ColorText) l.ForeColor = OnColor;
l.Text = "On";
}
else
{
//ligth
e.Graphics.FillRectangle(OffPen, (indent + 2), 2, this.Size.Width - (indent + 4), this.Size.Height - 4);
//Toggle
e.Graphics.DrawRectangle(ControlPen, indent , -0, (toggleblocsize + 1), this.Size.Height - 1);
e.Graphics.FillRectangle(BlackPen, (indent+1) , -1,(toggleblocsize), this.Size.Height + 1);
if (ColorText) l.ForeColor = this.ForeColor;
l.Text = "Off";
}
this.Controls.Add(l);
}
public override Size GetPreferredSize(Size proposedSize)
{
return new Size(80, 18);
}
}
It is not that I can't live with a flat tapcontrol it is just the why it doesn't work that bugs me ...
Any help would be greatly appreciated :)
Lastly some visual documentation of the problems:
Here is how it should work:
This is with a tap on normal

Got it fixed so that it now work, turns out that there was a few things wrong.
First of the base class was wrong, it should be a control
public class ToggleSwith : Control
and the on paint event changed to this
protected override void OnPaint(PaintEventArgs e)
{
//this.Controls.Clear();
int toggleblocsize = (int)this.Size.Width / 6;
int indent = 23;
int labelx = 2;
// Declare and instantiate a new pen.
SolidBrush OffPen = new SolidBrush(this.OffColor);
SolidBrush OnPen = new SolidBrush(this.OnColor);
Rectangle texttangle = new Rectangle(new Point(labelx, 0), new Size(indent - labelx, this.Size.Height));
SolidBrush BackgroundBrush = new SolidBrush(this.Parent.BackColor);
SolidBrush ToggleBrush = new SolidBrush(SystemColors.ControlText);
SolidBrush TextBrush = new SolidBrush(SystemColors.ControlText);
Pen ControlDarkPen = new Pen(SystemColors.ControlDark);
Pen ControlPen = new Pen(SystemColors.Control);
e.Graphics.FillRectangle(BackgroundBrush, 0, 0, this.Size.Width, this.Size.Height);
e.Graphics.FillRectangle(new SolidBrush(BackColor), indent, 0, this.Size.Width - indent, this.Size.Height);
e.Graphics.DrawRectangle(ControlDarkPen, indent, -0, this.Size.Width - (indent + 1), this.Size.Height - 1);
if (!this.Enabled)
{
OffPen = new SolidBrush(SystemColors.Control);
OnPen = new SolidBrush(SystemColors.Control);
ToggleBrush = new SolidBrush(SystemColors.ControlDark);
TextBrush = new SolidBrush(SystemColors.Control);
}
if (this._Checked)
{
//ligth
e.Graphics.FillRectangle(OnPen, (indent + 2), 2, this.Size.Width - (indent + 4), this.Size.Height - 4);
//Toggle
e.Graphics.DrawRectangle(ControlPen, this.Size.Width - (toggleblocsize + 1), -0, this.Size.Width - (indent + 1), this.Size.Height - 1);
e.Graphics.FillRectangle(ToggleBrush, this.Size.Width - (toggleblocsize), -1, this.Size.Width, this.Size.Height + 1);
if (ColorText && this.Enabled) TextBrush = new SolidBrush(OnColor);//_label.ForeColor = OnColor;
// _label.Text = "On";
// Draw string to screen.
TextRenderer.DrawText(e.Graphics, OnText, this.Font, texttangle, TextBrush.Color, this.Parent.BackColor,
TextFormatFlags.HorizontalCenter |
TextFormatFlags.VerticalCenter |
TextFormatFlags.GlyphOverhangPadding);
}
else
{
//ligth
e.Graphics.FillRectangle(OffPen, (indent + 2), 2, this.Size.Width - (indent + 4), this.Size.Height - 4);
//Toggle
e.Graphics.DrawRectangle(ControlPen, indent, -0, (toggleblocsize + 1), this.Size.Height - 1);
e.Graphics.FillRectangle(ToggleBrush, (indent + 1), -1, (toggleblocsize), this.Size.Height + 1);
if (ColorText && this.Enabled) TextBrush = new SolidBrush(SystemColors.ControlText);
// Draw string to screen.
TextRenderer.DrawText(e.Graphics, OffText, this.Font, texttangle, TextBrush.Color, this.Parent.BackColor,
TextFormatFlags.HorizontalCenter |
TextFormatFlags.VerticalCenter |
TextFormatFlags.GlyphOverhangPadding);
}
that got the graphics result i was looking for.

Related

Redesign TabControl Menu c# (New colors, no borders)

The basic TabControl doesn't fit my needs design wise and needed a redesign.
The things that i needed were:
No borders
Gray background with white text for the selected tab
Black background with gray text for not selected tab
No doted line inside the selected tab (this one is a bit low priority)
I managed to fix some of these issues by creating a new class except for the last two. Seeing my limited experience (first time doing something like this) I was hoping somebody here could point me in the right direction.
Below an illustration of what it currently is and how I would want it to look. And of course the code of the class I used to do this.
What it looks like:
What i want it to look like:
The code:
class CustomTabControl : TabControl
{
public CustomTabControl(): base()
{
this.DrawMode = TabDrawMode.OwnerDrawFixed;
this.DrawItem += new DrawItemEventHandler(tabControl1_DrawItem);
}
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Font fntTab;
Brush bshBack;
Brush bshFore;
if (e.Index == this.SelectedIndex)
{
fntTab = new Font(e.Font, FontStyle.Bold);
bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.FromArgb(64,64,64), Color.FromArgb(0, 0, 0), System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
bshFore = Brushes.White;
}
else
{
fntTab = new Font(e.Font, FontStyle.Bold);
bshBack = new System.Drawing.Drawing2D.LinearGradientBrush(e.Bounds, Color.FromArgb(0,0,0), Color.FromArgb(0, 0, 0), System.Drawing.Drawing2D.LinearGradientMode.BackwardDiagonal);
bshFore = Brushes.Gray;
}
string tabName = this.TabPages[e.Index].Text;
StringFormat sftTab = new StringFormat();
e.Graphics.FillRectangle(bshBack, e.Bounds);
Rectangle recTab = e.Bounds;
recTab = new Rectangle(recTab.X +3 , recTab.Y+3, recTab.Width, recTab.Height );
e.Graphics.DrawString(tabName, fntTab, bshFore, recTab, sftTab);
Rectangle r = this.GetTabRect(this.TabPages.Count - 1);
RectangleF tf = new RectangleF(r.X + r.Width, r.Y - 2, this.Width - (r.X + r.Width) + 0, r.Height + 4);
Brush b = Brushes.Black;
e.Graphics.FillRectangle(b, tf);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0005)
{
int Width = unchecked((short)m.LParam);
int Height = unchecked((short)((uint)m.LParam >> 16));
Region = new Region(new Rectangle(4, 2, Width - 8, Height - 6));
}
base.WndProc(ref m);
}
}
(And suggestions on improving this class are welcome.)

Translucent circular Control with text

I am working on a project wherein I need to add a Control with the shape of a Circle with some text in the middle.
My problem is the circle is too small, when I resize it, it overlaps other controls. I want to draw the circle same width as the square.
Otherwise. how can I make the Control's background transparent?
I am using the code below:
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
{
using (Graphics graphics = Graphics.FromImage(bitmap))
{
graphics.SmoothingMode = SmoothingMode.HighQuality;
graphics.Clear(this.BackColor);
using (SolidBrush brush = new SolidBrush(this._FillColor))
{
graphics.FillEllipse(brush, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12);
}
Brush FontColor = new SolidBrush(this.ForeColor);
SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font);
graphics.DrawString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font, FontColor, Convert.ToInt32((Width / 2 - MS.Width / 2) + 2), Convert.ToInt32((Height / 2 - MS.Height / 2) + 3));
bitmap.MakeTransparent(this.BackColor);
e.Graphics.DrawImage(bitmap, 0, 0);
graphics.Dispose();
bitmap.Dispose();
}
}
}
This is a Custom Control derived from Control, which can be made translucent.
The interface is a colored circle which can contain a couple of numbers.
The Control exposes these custom properties:
Opacity: The level of opacity of the control BackGround [0, 255]
InnerPadding: The distance between the inner rectangle, which defines the circle bounds and the control bounds.
FontPadding: The distance between the Text and the Inner rectangle.
Transparency is obtained overriding CreateParams, then setting ExStyle |= WS_EX_TRANSPARENT;
The Control.SetStyle() method is used to modify the control behavior, adding these ControlStyles:
▶ ControlStyles.Opaque: prevents the painting of a Control's BackGround, so it's not managed by the System. Combined with CreateParams to set the Control's Extended Style to WS_EX_TRANSPARENT, the Control becomes completely transparent.
▶ ControlStyles.SupportsTransparentBackColor the control accepts Alpha values for it's BackGround color. Without also setting ControlStyles.UserPaint it won't be used to simulate transparency. We're doing that ourselves with other means.
To see it at work, create a new Class file, substitute all the code inside with this code preserving the NameSpace and build the Project/Solution.
The new Custom Control will appear in the ToolBox. Drop it on a Form. Modify its custom properties as needed.
A visual representation of the control:
Note and disclaimer:
This is a prototype Control, the custom Designer is missing (cannot post that here, too much code, also connected to a framework).
As presented here, it can be used to completely overlap other Controls in a Form or other containers. Partial overlapping is not handled in this simplified implementation.
The Font is hard-coded to Segoe UI, since this Font has a base-line that simplifies the position of the text in the middle of the circular area.
Other Fonts have a different base-line, which requires more complex handling.
See: TextBox with dotted lines for typing for the base math.
using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows.Forms;
[DesignerCategory("Code")]
public class RoundCenterLabel : Label, INotifyPropertyChanged, ISupportInitialize
{
private const int WS_EX_TRANSPARENT = 0x00000020;
private bool IsInitializing = false;
private Point MouseDownLocation = Point.Empty;
private readonly int fontPadding = 4;
private Font m_CustomFont = null;
private Color m_BackGroundColor;
private int m_InnerPadding = 0;
private int m_FontPadding = 25;
private int m_Opacity = 128;
public event PropertyChangedEventHandler PropertyChanged;
public RoundCenterLabel() => InitializeComponent();
private void InitializeComponent()
{
SetStyle(ControlStyles.Opaque |
ControlStyles.SupportsTransparentBackColor |
ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
m_CustomFont = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
BackColor = Color.LimeGreen;
ForeColor = Color.White;
}
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
public new Font Font
{
get => m_CustomFont;
set {
m_CustomFont = value;
if (IsInitializing) return;
FontAdapter(value, DeviceDpi);
NotifyPropertyChanged();
}
}
public override string Text {
get => base.Text;
set { base.Text = value;
NotifyPropertyChanged();
}
}
public int InnerPadding {
get => m_InnerPadding;
set {
if (IsInitializing) return;
m_InnerPadding = ValidateRange(value, 0, ClientRectangle.Height - 10);
NotifyPropertyChanged(); }
}
public int FontPadding {
get => m_FontPadding;
set {
if (IsInitializing) return;
m_FontPadding = ValidateRange(value, 0, ClientRectangle.Height - 10);
NotifyPropertyChanged();
}
}
public int Opacity {
get => m_Opacity;
set { m_Opacity = ValidateRange(value, 0, 255);
UpdateBackColor(m_BackGroundColor);
NotifyPropertyChanged();
}
}
public override Color BackColor {
get => m_BackGroundColor;
set { UpdateBackColor(value);
NotifyPropertyChanged();
}
}
protected override void OnLayout(LayoutEventArgs e)
{
base.OnLayout(e);
base.AutoSize = false;
}
private void NotifyPropertyChanged([CallerMemberName] string PropertyName = null)
{
InvalidateParent();
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
MouseDownLocation = e.Location;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left) {
var loc = new Point(Left + (e.X - MouseDownLocation.X), Top + (e.Y - MouseDownLocation.Y));
InvalidateParent();
BeginInvoke(new Action(() => Location = loc));
}
}
private void InvalidateParent()
{
Parent?.Invalidate(Bounds, true);
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
using (var format = new StringFormat(StringFormatFlags.LineLimit | StringFormatFlags.NoWrap, CultureInfo.CurrentUICulture.LCID))
{
format.LineAlignment = StringAlignment.Center;
format.Alignment = StringAlignment.Center;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
using (var circleBrush = new SolidBrush(m_BackGroundColor))
using (var foreBrush = new SolidBrush(ForeColor))
{
FontAdapter(m_CustomFont, e.Graphics.DpiY);
RectangleF rect = InnerRectangle();
e.Graphics.FillEllipse(circleBrush, rect);
e.Graphics.DrawString(Text, m_CustomFont, foreBrush, rect, format);
};
};
}
public void BeginInit() => IsInitializing = true;
public void EndInit()
{
IsInitializing = false;
Font = new Font("Segoe UI", 50, FontStyle.Regular, GraphicsUnit.Pixel);
FontPadding = m_FontPadding;
InnerPadding = m_InnerPadding;
}
private RectangleF InnerRectangle()
{
(float Min, _) = GetMinMax(ClientRectangle.Height, ClientRectangle.Width);
var size = new SizeF(Min - (m_InnerPadding / 2), Min - (m_InnerPadding / 2));
var position = new PointF((ClientRectangle.Width - size.Width) / 2,
(ClientRectangle.Height - size.Height) / 2);
return new RectangleF(position, size);
}
private void FontAdapter(Font font, float dpi)
{
RectangleF rect = InnerRectangle();
float fontSize = ValidateRange(
(int)(rect.Height - m_FontPadding), 6,
(int)(rect.Height - m_FontPadding)) / (dpi / 72.0F) - fontPadding;
m_CustomFont.Dispose();
m_CustomFont = new Font(font.FontFamily, fontSize, font.Style, GraphicsUnit.Pixel);
}
private void UpdateBackColor(Color color)
{
m_BackGroundColor = Color.FromArgb(m_Opacity, Color.FromArgb(color.R, color.G, color.B));
base.BackColor = m_BackGroundColor;
}
private int ValidateRange(int Value, int Min, int Max)
=> Math.Max(Math.Min(Value, Max), Min); // (Value < Min) ? Min : ((Value > Max) ? Max : Value);
private (float, float) GetMinMax(float Value1, float Value2)
=> (Math.Min(Value1, Value2), Math.Max(Value1, Value2));
}

Duplicate Tooltip style and size for custom draw

I created my custom Tooltip, but what I need is that it will be with the same style as system draws it when you do not switch on the OwnerDraw flag.
How can I create custom tooltip which looks exactly like the "original" one?
ttSessionInfo.ToolTipTitle = UiTranslator.Instance.GetLabel(UiLabels.DC_DSE_Session);
var toolTipSessionsText = sessions.Aggregate(
new StringBuilder(),
(p_strBuilder, p_session) => p_strBuilder.AppendLine(string.Format("{0}: {1}", p_session.SessionName,
p_session.IsConnected ? connectedText : disconnectedText))).ToString();
ttSessionInfo.SetToolTip(LiveUpdatePb, toolTipSessionsText);
Result is:
I need the same tooltip exactly to show on another control, but to paint ,lets say, the second row "Alex Session: Connected" with red color.
I added a sample that re-implements ToolTip class and codes to use it.
class:
class CustomToolTip : ToolTip
{
public CustomToolTip()
{
this.OwnerDraw = true;
this.Popup += new PopupEventHandler(this.OnPopup);
this.Draw += new DrawToolTipEventHandler(this.OnDraw);
}
string m_EndSpecialText;
Color m_EndSpecialTextColor =Color.Red;
public Color EndSpecialTextColor
{
get { return m_EndSpecialTextColor; }
set { m_EndSpecialTextColor = value; }
}
public string EndSpecialText
{
get { return m_EndSpecialText; }
set { m_EndSpecialText = value; }
}
private void OnPopup(object sender, PopupEventArgs e) // use this event to set the size of the tool tip
{
e.ToolTipSize = new Size(200, 100);
}
private void OnDraw(object sender, DrawToolTipEventArgs e) // use this event to customise the tool tip
{
Graphics g = e.Graphics;
LinearGradientBrush b = new LinearGradientBrush(e.Bounds,
Color.GreenYellow, Color.MintCream, 45f);
g.FillRectangle(b, e.Bounds);
g.DrawRectangle(new Pen(Brushes.Red, 1), new Rectangle(e.Bounds.X, e.Bounds.Y,
e.Bounds.Width - 1, e.Bounds.Height - 1));
//g.DrawString(e.ToolTipText, new Font(e.Font, FontStyle.Bold), Brushes.Silver,
// new PointF(e.Bounds.X + 6, e.Bounds.Y + 6)); // shadow layer
g.DrawString(e.ToolTipText, new Font(e.Font, FontStyle.Bold), Brushes.Black,
new PointF(e.Bounds.X + 5, e.Bounds.Y + 5)); // top layer
SolidBrush brush = new SolidBrush(EndSpecialTextColor);
g.DrawString(EndSpecialText, new Font(e.Font, FontStyle.Bold), brush,
new PointF(e.Bounds.X + 5, e.Bounds.Bottom - 15)); // top layer
brush.Dispose();
b.Dispose();
}
}
following the use of above class
private void button1_Click(object sender, EventArgs e)
{
CustomToolTip toolTip1 = new CustomToolTip();
toolTip1.ShowAlways = true;
toolTip1.SetToolTip(button1, "Click me to execute.");
toolTip1.EndSpecialText = "Hello I am special";
}

How to make a floating control

I would like to create a control the floats (potentially) outside the bounds of it's containing form. Is this possible? How may I do it?
This would function much like Context Menu's only I need to be able to add other controls to it such as buttons and images.
You want a Form with it's FormBorderStyle set to None, if you want it to behave like a context menu then you'll need to tie showing it to the appropriate event handler in your main form. Simple example below of setting the location and calling show from a mouse click event handler.
MyForm form = new MyForm();
form.Location = PointToScreen(new Point(e.X, e.Y));
form.Show();
It is possible, the TopLevel property controls this. However, the designer doesn't support them well, hard to keep control over controls that are also top-level windows at design time.
Beyond components like ToolTip and ContextMenuStrip, there is exactly one class that is top-level by design, the Form class. Set its FormBorderStyle to None and ControlBox to False to create a basic top-level window that you can use and populate with other controls.
Take a look at the DockPanel Suite source and adopt the technique.
here is u can made for all Control floating Style
private void Panel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
Panel.Left += e.X - PanelMouseDownLocation.X;
Panel.Top += e.Y - PanelMouseDownLocation.Y;
}
}
private void Panel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) PanelMouseDownLocation = e.Location;
}
public Point PanelMouseDownLocation { get; set; }
It would need to be a separate window (much like a context menu actually is) -- you could wrap it as a control, that displays a modeless form (which would even give you the option for non rectangular windows if you really wanted to). As you could create the window from a non-visible control from the parent form, you can maintain a reference to the child for handling inter-form communication.
Have your UserControl override CreateParams. For example:
[DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
public static extern IntPtr GetDesktopWindow();
protected override CreateParams CreateParams
{
get
{
var cp = base.CreateParams;
cp.ExStyle &= 0x00080000; // WS_EX_LAYERED
cp.Style = 0x40000000 | 0x4000000; // WS_CHILD | WS_CLIPSIBLINGS
cp.Parent = GetDesktopWindow();
return cp;
}
}
This may have unintended effects (including not working well with Designer). I am choosing to follow one of the above patterns, but I thought it was worth mentioning here. Lookup CreateParams to see its purpose. (This option was gleaned from this page.)
This worked for me
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Windows.Forms;
using LollipopUIControls.UIManagers;
namespace Gamasis.Apps.Controls
{
public class FloatingButton : Button
{
public FloatingButton()
{
SetStyle((ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint), true);
DoubleBuffered = true;
Size = new Size(50, 50);
BackColor = Color.Transparent;
SF.Alignment = StringAlignment.Center;
SF.LineAlignment = StringAlignment.Center;
AnimationTimer.Tick += new EventHandler(AnimationTick);
}
#region Variables
Timer AnimationTimer = new Timer { Interval = 1 };
FontManager font = new FontManager();
StringFormat SF = new StringFormat();
Rectangle StringRectangle;
bool Focus = false;
int margintop = 0, marginleft = 0, marginright = 0, marginBottom = 0;
int xx;
int yy;
float SizeAnimation = 0;
float SizeIncNum;
string fontcolor = "#FAFAFA";
string Backcolor = "#039BE5";
Color EnabledBGColor;
Color EnabledBorderColor;
Color StringColor;
Color DisabledBGColor = ColorTranslator.FromHtml("#B0BEC5");
Color DisabledStringColor = ColorTranslator.FromHtml("#FAFAFA");
Color NonColor = ColorTranslator.FromHtml("#e3e5e7");
Image bGImage = null;
#endregion
#region Properties
[Category("Custom")]
public string BGColor
{
get { return Backcolor; }
set
{
Backcolor = value;
Invalidate();
}
}
[Category("Custom")]
public string FontColor
{
get { return fontcolor; }
set
{
fontcolor = value;
Invalidate();
}
}
[Browsable(false)]
public Font Font
{
get { return base.Font; }
set { base.Font = value; }
}
[Browsable(false)]
public Color ForeColor
{
get { return base.ForeColor; }
set { base.ForeColor = value; }
}
[Category("Custom")]
public Image BGImage
{
get { return bGImage; }
set { bGImage = value; }
}
ImageSizeLevel bGimgSize = ImageSizeLevel.peque2;
public ImageSizeLevel BGimgSize
{
get { return bGimgSize; }
set { bGimgSize = value; }
}
#endregion
#region Events
protected override void OnMouseEnter(EventArgs e)
{
base.OnMouseEnter(e);
EnabledBGColor = Color.FromArgb(30, ColorTranslator.FromHtml(BGColor));//StringColor);
EnabledBorderColor = Color.FromArgb(20, ColorTranslator.FromHtml(BGColor));//StringColor);
Refresh();
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
EnabledBGColor = ColorTranslator.FromHtml(BGColor);
EnabledBorderColor = ColorTranslator.FromHtml(BGColor);
Refresh();
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
EnabledBGColor = Color.FromArgb(30, StringColor);
Refresh();
xx = e.X;
yy = e.Y;
Focus = true;
AnimationTimer.Start();
Invalidate();
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Focus = false;
AnimationTimer.Start();
Invalidate();
}
protected override void OnTextChanged(System.EventArgs e)
{
base.OnTextChanged(e);
Invalidate();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
//StringRectangle = new Rectangle(3, 0, Width - 6, Height - 6);
}
#endregion
protected override void OnResize(System.EventArgs e)
{
base.OnResize(e);
//SizeIncNum = Width / 34;
SizeIncNum = Width / 10;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
var G = e.Graphics;
#region Default rectangle
//G.SmoothingMode = SmoothingMode.HighQuality | SmoothingMode.AntiAlias;
//G.Clear(Parent.BackColor);
//StringColor = ColorTranslator.FromHtml(fontcolor);
//var BG = DrawHelper.CreateRoundRect(1, 1, Width - 3, Height - 3, 1);
//Region region = new Region(BG);
//G.FillPath(new SolidBrush(Enabled ? EnabledBGColor : Color.White), BG);
//G.DrawPath(new Pen(Enabled ? EnabledBorderColor : Color.White), BG);
//G.SetClip(region, CombineMode.Replace);
////The Ripple Effect
//G.FillEllipse(new SolidBrush(Color.FromArgb(30, StringColor)), xx - (SizeAnimation / 2), yy - (SizeAnimation / 2), SizeAnimation, SizeAnimation);
//G.DrawString(Text, font.Roboto_Medium10, new SolidBrush(Enabled ? StringColor : DisabledStringColor), R, SF);
#endregion
#region Circle
//G.SmoothingMode = SmoothingMode.AntiAlias;
//G.Clear(BackColor);
//GraphicsPath bgbtn = new GraphicsPath();
//bgbtn.AddEllipse(0, 0, Width - 5, Height - 5);
//GraphicsPath bgShadow = new GraphicsPath();
//bgShadow.AddEllipse(0, 0, Width - 2, Height - 2);
//G.FillPath(new SolidBrush(NonColor), bgShadow);
//G.DrawPath(new Pen(NonColor), bgShadow);
//G.FillPath(new SolidBrush(Color.DeepSkyBlue), bgbtn);
//G.DrawPath(new Pen(Color.DeepSkyBlue), bgbtn);
#endregion
///----------------------------
G.SmoothingMode = SmoothingMode.AntiAlias;
G.Clear(Parent.BackColor);
StringColor = ColorTranslator.FromHtml(fontcolor);
//var BG = DrawHelper.CreateRoundRect(1, 1, Width - 3, Height - 3, 1);
//Círculo principal
GraphicsPath bgbtn = new GraphicsPath();
bgbtn.AddEllipse(2, 0, Width - 6, Height - 6);
//Círculo para la sombra
GraphicsPath bgShadow = new GraphicsPath();
bgShadow.AddEllipse(2, 4, Width - 6, Height - 6);
// se dibuja la sombra
G.FillPath(new SolidBrush(NonColor), bgShadow);
G.DrawPath(new Pen(NonColor), bgShadow);
//sedibuja el círculo principal sobre la sombra
G.FillPath(new SolidBrush(Enabled ? ColorTranslator.FromHtml(BGColor) : DisabledBGColor), bgbtn);
G.DrawPath(new Pen(Enabled ? ColorTranslator.FromHtml(BGColor) : DisabledBGColor), bgbtn);
// Se da a la región forma de círculo/elipse
Region region = new Region(bgbtn);//BG);
G.SetClip(region, CombineMode.Replace);
//The Ripple Effect
if (Enabled)
G.FillEllipse(new SolidBrush(Color.FromArgb(30, EnabledBGColor)), xx - (SizeAnimation / 2), yy - (SizeAnimation / 2), SizeAnimation, SizeAnimation);
StringRectangle = new Rectangle((int)bgbtn.GetBounds().Location.X, (int)bgbtn.GetBounds().Location.Y,
(int)bgbtn.GetBounds().Size.Width, (int)bgbtn.GetBounds().Size.Height);
G.DrawString(Text, font.Roboto_Medium15, new SolidBrush(Enabled ? StringColor : DisabledStringColor), StringRectangle, SF);
if (bGImage != null)
{
float imgX = 0, imgY = 0;
imgY = (bgbtn.GetBounds().Size.Height - (int)bGimgSize) / 2;
imgX = ((bgbtn.GetBounds().Size.Width - (int)bGimgSize) + 2) / 2;
G.DrawImage(bGImage, imgX, imgY, (float)bGimgSize, (float)bGimgSize);
}
}
protected void AnimationTick(object sender, EventArgs e)
{
if (Focus)
{
if (SizeAnimation < Width + 250)
{
SizeAnimation += SizeIncNum;
this.Invalidate();
}
}
else
{
if (SizeAnimation > 0)
{
SizeAnimation = 0;
this.Invalidate();
}
}
}
public enum ImageSizeLevel
{
peque = 12, peque1 = 24, peque2 = 32,
maso = 48, maso1 = 56, maso2 = 64,
grande = 72, grande1 = 86, grande2 = 96,
monstruo = 128, monstruo1 = 256, monstruo2 = 512
}
}
}

Placing Images and Strings with a C# Combobox

I need to create a dropdown menu, or combobox, for a Windows Forms application which contains a small image and then a string of text next to it. Basically, you can think of each 'row' in the dropdown as needing to have an icon and then the name of the icon to the right of the icon. I am having trouble doing this -- in fact, I've been completely unsuccessful. Does anyone know of a way to accomplish this task? Any help will be greatly appreciated. Thanks!
I was able to come up with some very simple code to perform this (see snippet below). The code creates a control that is a dropdown control which shows a small colored square and that color's name in the same row (see photo). Thanks for the links provided for this back when it was originally posted! Hopefully this control can help someone else out in the future.
Image:
Code:
class ColorSelector : ComboBox
{
public ColorSelector()
{
DrawMode = DrawMode.OwnerDrawFixed;
DropDownStyle = ComboBoxStyle.DropDownList;
}
// Draws the items into the ColorSelector object
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
DropDownItem item = new DropDownItem(Items[e.Index].ToString());
// Draw the colored 16 x 16 square
e.Graphics.DrawImage(item.Image, e.Bounds.Left, e.Bounds.Top);
// Draw the value (in this case, the color name)
e.Graphics.DrawString(item.Value, e.Font, new
SolidBrush(e.ForeColor), e.Bounds.Left + item.Image.Width, e.Bounds.Top + 2);
base.OnDrawItem(e);
}
}
public class DropDownItem
{
public string Value
{
get { return value; }
set { this.value = value; }
}
private string value;
public Image Image
{
get { return img; }
set { img = value; }
}
private Image img;
public DropDownItem() : this("")
{}
public DropDownItem(string val)
{
value = val;
this.img = new Bitmap(16, 16);
Graphics g = Graphics.FromImage(img);
Brush b = new SolidBrush(Color.FromName(val));
g.DrawRectangle(Pens.White, 0, 0, img.Width, img.Height);
g.FillRectangle(b, 1, 1, img.Width - 1, img.Height - 1);
}
public override string ToString()
{
return value;
}
}
Very helpful..
some optimisations :
public sealed class ColorSelector : ComboBox
{
public ColorSelector()
{
DrawMode = DrawMode.OwnerDrawFixed;
DropDownStyle = ComboBoxStyle.DropDownList;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
e.DrawBackground();
e.DrawFocusRectangle();
if (e.Index >= 0 && e.Index < Items.Count)
{
DropDownItem item = (DropDownItem)Items[e.Index];
e.Graphics.DrawImage(item.Image, e.Bounds.Left, e.Bounds.Top);
e.Graphics.DrawString(item.Value, e.Font, new SolidBrush(e.ForeColor), e.Bounds.Left + item.Image.Width, e.Bounds.Top + 2);
}
base.OnDrawItem(e);
}
}
and ...
public sealed class DropDownItem
{
public string Value { get; set; }
public Image Image { get; set; }
public DropDownItem()
: this("")
{ }
public DropDownItem(string val)
{
Value = val;
Image = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(Image))
{
using (Brush b = new SolidBrush(Color.FromName(val)))
{
g.DrawRectangle(Pens.White, 0, 0, Image.Width, Image.Height);
g.FillRectangle(b, 1, 1, Image.Width - 1, Image.Height - 1);
}
}
}
public override string ToString()
{
return Value;
}
}
NOTE: This code is from user que dal's optimization
If you wish to have a string that isn't just the name of the color, change DropDownItem to have 2 arguments, the string and the color, then just change how the brush sets the color, as such:
public DropDownItem(string val, Color color)
{
Value = val;
Image = new Bitmap(16, 16);
using (Graphics g = Graphics.FromImage(Image))
{
using (Brush b = new SolidBrush(color))
{
g.DrawRectangle(Pens.White, 0, 0, Image.Width, Image.Height);
g.FillRectangle(b, 1, 1, Image.Width - 1, Image.Height - 1);
}
}
}
You must then change the dropdown item as such:
public DropDownItem()
: this("", Color.Empty)
{}
Hope this was helpful :)
I resolved the problem, i did this:
ComboBox MarcadorNS = new ComboBox();
MarcadorNS.Height = 30;
MarcadorNS.Width = 150;
MarcadorNS.SelectedValuePath = "Uid";
foreach (var temporalItem in GetPredefinedKinds())
{
Image ImagenCombo = new Image();
ImagenCombo.Source =
new BitmapImage(new Uri(
"Imagenes/Marcadores/" +
temporalItem.Name.ToLower() + ".png", UriKind.Absolute));
ImagenCombo.Height = 28;
ImagenCombo.Width = 28;
ImagenCombo.VerticalAlignment = VerticalAlignment.Top;
ImagenCombo.HorizontalAlignment = HorizontalAlignment.Left;
Label textoCombo = new Label();
textoCombo.VerticalAlignment = VerticalAlignment.Top;
textoCombo.HorizontalAlignment = HorizontalAlignment.Left;
textoCombo.Content = BaseDatos.NombresDeMarcadores(temporalItem.ToString());
Grid GridCombo = new Grid();
GridCombo.Uid = ObtenerMarcador(temporalItem.ToString());
StackPanel stackCombo = new StackPanel();
stackCombo.Orientation = Orientation.Horizontal;
stackCombo.Children.Add(ImagenCombo);
stackCombo.Children.Add(textoCombo);
GridCombo.Children.Add(stackCombo);
MarcadorNS.Items.Add(GridCombo);
}
Not sure about images but this should work for the strings:
comboBox.Items.Add("String");

Categories