Disable WinForms ProgressBar animation - c#

Is there a possbility to disable animation of the progress bar?
I need it for some pocess which is paused and not running at the moment. An average user would think the process is running if the progress bar is being blinking.
The advice to create own progress bar control is not what I'm looking for.

You can use the Vista progress bar's paused state, like this:
// Assuming a Form1 with 3 ProgressBar controls
private void Form1_Load(object sender, EventArgs e)
{
SendMessage(progressBar2.Handle,
0x400 + 16, //WM_USER + PBM_SETSTATE
0x0003, //PBST_PAUSED
0);
SendMessage(progressBar3.Handle,
0x400 + 16, //WM_USER + PBM_SETSTATE
0x0002, //PBST_ERROR
0);
}
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern uint SendMessage(IntPtr hWnd,
uint Msg,
uint wParam,
uint lParam);

My workaround was to use a Panel Control instead of ProgressBar. I changed BackColor, BorderStyle (to Fixed3D) and I manipulate its Width to display needed level of progress. I assumed that 100% of progress is equal to Width of the Form.

The standard means of communicating to a user that an action is either paused or can't be accurately measured is to use the marquee display style.
progressBar1.Style = ProgressBarStyle.Marquee;
This style ignores the Maximum and Value properties and displays a progress bar "segment" that continually moves across the progress bar and loops around (it doesn't fill the progress bar, it moves what looks like a section of the bar all the way across the control and around to the beginning again.)

What you will want to do is set the style on this control specifically to override the theme changes. This article gives you a bit of information.

You could override the OnPaint() of the progressbar. You don't actually need to rewrite the whole thing, you just have to inherit the progressbar and override OnPaint like this:
public class my_progress_bar : ProgressBar {
public Brush brush;
public my_progress_bar() {
this.SetStyle(ControlStyles.UserPaint, true);
brush = Brushes.ForestGreen;
}
protected override void OnPaint(PaintEventArgs e)
{
//base.OnPaint(e);
Rectangle rectangle = e.ClipRectangle;
rectangle.Width = (int)(rectangle.Width * ((double)Value / Maximum)) - 4;
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
rectangle.Height = Height - 4;
e.Graphics.FillRectangle(brush, 2, 2, rectangle.Width, rectangle.Height);
}
}

Paste this as to code. This will rewrite the progress bar, it's also customizable to color.
public class CProgressBar : ProgressBar
{
public Color MyColor {
get { return _color; }
set {
_color = value;
MyBrush = new SolidBrush(_color);
Invalidate();
}
}
private Color _color = Color.Green;
public CProgressBar()
{
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true);
}
public int Value {
get { return _value; }
set {
_value = value;
Invalidate();
}
}
private int _value;
private SolidBrush MyBrush = new SolidBrush(_color);
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillRectangle(MyBrush, new Rectangle(0, 0, Width * (_value / Maximum), Height));
}
}

Related

How to align Combobox values on center, without spaces? [duplicate]

I want to align my text in combo box so that it will show in the center of combobox tell me how to do this also you can see there is a default border around a combo box when it is in focus how can i remove that border also
Kindly solve my two problems
Thanks
This article will help you: http://blog.michaelgillson.org/2010/05/18/left-right-center-where-do-you-align/
The trick is to set the DrawMode-Property of the ComboBox to OwnerDrawFixed as well as subscribe to its event DrawItem.
Your event should contain the following code:
// Allow Combo Box to center aligned
private void cbxDesign_DrawItem(object sender, DrawItemEventArgs e)
{
// By using Sender, one method could handle multiple ComboBoxes
ComboBox cbx = sender as ComboBox;
if (cbx != null)
{
// Always draw the background
e.DrawBackground();
// Drawing one of the items?
if (e.Index >= 0)
{
// Set the string alignment. Choices are Center, Near and Far
StringFormat sf = new StringFormat();
sf.LineAlignment = StringAlignment.Center;
sf.Alignment = StringAlignment.Center;
// Set the Brush to ComboBox ForeColor to maintain any ComboBox color settings
// Assumes Brush is solid
Brush brush = new SolidBrush(cbx.ForeColor);
// If drawing highlighted selection, change brush
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
brush = SystemBrushes.HighlightText;
// Draw the string
e.Graphics.DrawString(cbx.Items[e.Index].ToString(), cbx.Font, brush, e.Bounds, sf);
}
}
}
To right align the items you can simply replace StringAlignment.Center with StringAlignment.Far.
This isn't supported for ComboBox. The exact reasons are lost in the fog of time, ComboBox has been around since the early nineties, but surely has something to do with the awkwardness of getting the text in the textbox portion to line up with the text in the dropdown. Custom drawing with DrawItem cannot solve it either, that only affects the appearance of the dropdown items.
As a possible workaround, you could perhaps do something outlandish like padding the item strings with spaces so they look centered. You'll need TextRenderer.MeasureText() to figure out how many spaces to add for each item.
The "border" you are talking about is not a border, it is the focus rectangle. You can't get rid of that either, Windows refuses to let you create a UI that won't show the control with the focus. Users that prefer the keyboard over the mouse care about that. No workaround for that one.
Set RightToLeft property to true.
It does NOT reverse the sequence of characters. It only right-justifies.
The post is a bit old but it may be still worth to say:
both requirements are possible for Windows Forms ComboBox:
Text align center (text area and the dropdown)
For the text area, find the Edit control and set the ES_CENTER style for the control.
For the dropdown items or the selected item in drop-down mode, to align text to center, just make the control owner-drawn and draw the text at center.
Get rid of focus rectangle
Make the control owner-drawn and just don't draw focus rectangle.
Example
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyComboBox : ComboBox
{
public MyComboBox()
{
DrawMode = DrawMode.OwnerDrawFixed;
}
[DllImport("user32.dll")]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
const int GWL_STYLE = -16;
const int ES_LEFT = 0x0000;
const int ES_CENTER = 0x0001;
const int ES_RIGHT = 0x0002;
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public int Width { get { return Right - Left; } }
public int Height { get { return Bottom - Top; } }
}
[DllImport("user32.dll")]
public static extern bool GetComboBoxInfo(IntPtr hWnd, ref COMBOBOXINFO pcbi);
[StructLayout(LayoutKind.Sequential)]
public struct COMBOBOXINFO
{
public int cbSize;
public RECT rcItem;
public RECT rcButton;
public int stateButton;
public IntPtr hwndCombo;
public IntPtr hwndEdit;
public IntPtr hwndList;
}
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
SetupEdit();
}
private int buttonWidth = SystemInformation.HorizontalScrollBarArrowWidth;
private void SetupEdit()
{
var info = new COMBOBOXINFO();
info.cbSize = Marshal.SizeOf(info);
GetComboBoxInfo(this.Handle, ref info);
var style = GetWindowLong(info.hwndEdit, GWL_STYLE);
style |= 1;
SetWindowLong(info.hwndEdit, GWL_STYLE, style);
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
base.OnDrawItem(e);
e.DrawBackground();
var txt = "";
if (e.Index >= 0)
txt = GetItemText(Items[e.Index]);
TextRenderer.DrawText(e.Graphics, txt, Font, e.Bounds,
ForeColor, TextFormatFlags.Left | TextFormatFlags.HorizontalCenter);
}
}
you can do something like this by adding space before Display member in your Query
for example :
combobox1.DataSource = Query(Select col1 , (' '+col2) as Col2 from tableName)
combobox1.DisplayMember = "Col2";
combobox1.ValueMember = "col1";

Effect of temporary variable on erasing the background of a GroupBox

The context:
Consider drawing a GroupBox with a gradient as a part of it's background.
Example:
Let's perform the following actions:
Create a class that inherits GroupBox.
Set it's FlatStyle property to FlatStyle.System.
override it's WndProc method.
Handle the WM_ERASEBKGND message, in which we draw the gradient.
Handle the WM_PRINTCLIENT message, where we call DefWndProc and return.(Will be needed later.)
Add a Label as it's child Control.(The Label's background must be transparent to be able to see the gradient behind it's Text.
Create a class that inherits Label.
override the WndProc method.
"Simulate transparency" by calling the DrawThemeParentBackground function to draw the GroupBox's background on the Label's Graphics.
The issue:
Depending on whether a temporary variable is used to hold the Graphics object, the end result varies, depicted with the code sample and image below:
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace MCVE
{
class GroupBox : System.Windows.Forms.GroupBox
{
const int WM_ERASEBKGND = 0x14;
const int WM_PRINTCLIENT = 0x318;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_ERASEBKGND:
base.WndProc(ref m);
using (var g = Graphics.FromHdc(m.WParam))//CASE 1
//using (var e = new PaintEventArgs(Graphics.FromHdc(m.WParam), ClientRectangle))//CASE 2
{
var e = new PaintEventArgs(g, ClientRectangle);//CASE 1
var r = new Rectangle(2, 12, Width - 4, Height - 2);
using (var b = new LinearGradientBrush(r, BackColor, SystemColors.Window, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(b, r);//Draw the gradient.
}
}
m.Result = new IntPtr(1);//Signal that no further drawing of the background is necessary by WM_PAINT.
return;
case WM_PRINTCLIENT:
DefWndProc(ref m);//Bypass GroupBox's internal handling so that actual painting is handled by Windows.
return;
}
base.WndProc(ref m);//Default processing of the rest of the messages.
}
};
class Label : System.Windows.Forms.Label
{
const int WM_ERASEBKGND = 0x14;
const int WM_PAINT = 0xF;
[DllImport("user32.dll")] static extern IntPtr BeginPaint(IntPtr hWnd, out PAINTSTRUCT lpPaint);
[DllImport("user32.dll")] static extern IntPtr EndPaint(IntPtr hWnd, ref PAINTSTRUCT lpPaint);
//Ask Windows to send a message to the parent to draw it's background in the current device context.
[DllImport("uxtheme.dll")] extern static int DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc, ref Rectangle pRect);
[StructLayout(LayoutKind.Sequential)]
struct PAINTSTRUCT
{
public IntPtr hdc;
public bool fErase;
public Rectangle rcPaint;
public bool fRestore;
public bool fIncUpdate;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] public byte[] rgcReserved;
};
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_ERASEBKGND:
var r = ClientRectangle;
DrawThemeParentBackground(Handle, m.WParam, ref r);
m.Result = new IntPtr(1);//Signal that no further drawing of the background is necessary by WM_PAINT.
return;
case WM_PAINT:
PAINTSTRUCT ps;
var hdc = BeginPaint(Handle, out ps);
EndPaint(Handle, ref ps);//Don't paint any text so that the gradient remains visible.
m.Result = IntPtr.Zero;
return;
}
base.WndProc(ref m);//Default processing of the rest of the messages.
}
};
static class Program
{
[STAThread] static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var form = new Form() { BackColor = SystemColors.Highlight };
var groupbox = new GroupBox() { Anchor = (AnchorStyles)15, FlatStyle = FlatStyle.System, Location = new Point(10, 10), Text = "groupBox1" };
form.Controls.Add(groupbox);
groupbox.Controls.Add(new Label() { FlatStyle = FlatStyle.System, Location = new Point(50, 50) });
Application.Run(form);
}
};
}
Running the above MCVE (CASE 1) produces the expected ouput as shown in the example image.
On commenting out the lines remarked CASE 1 and uncommenting the line marked CASE 2 gives the following undesired output:
The question:
Why does the removal of the temporary variable produce such a vastly different output?
Posting this as an answer for the sake of completeness.
As pointed out by Ivan Stoev, the non-owning PaintEventArgs does not call Dispose on the Graphics object.
This has visible side effects as the DC is reused by Windows in the WM_PRINTCLIENT Message, that is sent next to the WndProc.
Manually calling Dispose on the Graphics object confirms this.
using (var g = Graphics.FromHdc(m.WParam))
{
using (var e = new PaintEventArgs(g, ClientRectangle))
{
var r = new Rectangle(2, 12, Width - 4, Height - 2);
using (var b = new LinearGradientBrush(r, BackColor, SystemColors.Window, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(b, r);//Draw the gradient.
}
}
}
Can all this boil down to a simple derived class, without PInvoking?
This class derives from GroupBox, set it as Transparent using CreateParams CreateParams.ExStyle proeprty, enables support for Transparent colors with Control.SetStyle() and ControlStyles.SupportsTransparentBackColor style (this way you can better control the effect of the LinearGradientBrush) and overrides the OnPaintBackground() method to perform the painting.
It's just a basic example, but it can be tweaked in any other way and still be more portable.
You can drop any control on it.
class GradientGroupBox : GroupBox
{
private const int WS_EX_TRANSPARENT = 0x20;
public GradientGroupBox() => this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
Color gradFillTo = Color.FromArgb(200, SystemColors.Window);
Color gradFillFrom = Color.FromArgb(128, this.Parent.BackColor);
using (LinearGradientBrush gradientBrush = new LinearGradientBrush(this.ClientRectangle, gradFillFrom, gradFillTo, LinearGradientMode.Vertical))
{
e.Graphics.FillRectangle(gradientBrush, this.ClientRectangle);
}
}
protected override CreateParams CreateParams
{
get
{
CreateParams parameters = base.CreateParams;
parameters.ExStyle |= WS_EX_TRANSPARENT;
return parameters;
}
}
}

ScrollableControl draw border around entire control

I'm building custom user control that is based on ScrollableControl.
Right now I'm trying to add border around my control (similar to border that DataGridView has)
I'm able to draw border using:
e.Graphics.TranslateTransform(AutoScrollPosition.X*-1, AutoScrollPosition.Y*-1);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.DarkBlue, ButtonBorderStyle.Dashed);
but this draws border around ClientRectangle, not around whole control:
As you can see in the above picture, border isn't surrounding scrollbars as it does in DataGridView.
Can I draw border around entire control so that scrollbars get included in area surrounded by border?
EDIT:
Based on Textbox custom onPaint I am able to draw custom border, by overriding WndProc but I get this weird looking border flickering:
Here is full code I have so far:
internal class TestControl : ScrollableControl
{
private int _tileWidth = 100;
private int _tileHeight = 100;
private int _tilesX = 20;
private int _tilesY = 20;
public TestControl()
{
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
UpdateStyles();
ResizeRedraw = true;
AutoScrollMinSize = new Size(_tilesX*_tileWidth, _tilesY*_tileHeight);
}
private bool _test = true;
[DefaultValue(true)]
public bool Test
{
get { return _test; }
set
{
if(_test==value) return;
_test = value;
Update();
}
}
[DllImport("user32")]
private static extern IntPtr GetWindowDC(IntPtr hwnd);
struct RECT
{
public int left, top, right, bottom;
}
struct NCCALSIZE_PARAMS
{
public RECT newWindow;
public RECT oldWindow;
public RECT clientWindow;
IntPtr windowPos;
}
int clientPadding = 1;
int actualBorderWidth = 1;
Color borderColor = Color.Black;
protected override void WndProc(ref Message m)
{
//We have to change the clientsize to make room for borders
//if not, the border is limited in how thick it is.
if (m.Msg == 0x83 && _test) //WM_NCCALCSIZE
{
if (m.WParam == IntPtr.Zero)
{
RECT rect = (RECT)Marshal.PtrToStructure(m.LParam, typeof(RECT));
rect.left += clientPadding;
rect.right -= clientPadding;
rect.top += clientPadding;
rect.bottom -= clientPadding;
Marshal.StructureToPtr(rect, m.LParam, false);
}
else
{
NCCALSIZE_PARAMS rects = (NCCALSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(NCCALSIZE_PARAMS));
rects.newWindow.left += clientPadding;
rects.newWindow.right -= clientPadding;
rects.newWindow.top += clientPadding;
rects.newWindow.bottom -= clientPadding;
Marshal.StructureToPtr(rects, m.LParam, false);
}
}
if (m.Msg == 0x85 && _test) //WM_NCPAINT
{
base.WndProc(ref m);
IntPtr wDC = GetWindowDC(Handle);
using (Graphics g = Graphics.FromHdc(wDC))
{
ControlPaint.DrawBorder(g, new Rectangle(0, 0, Size.Width, Size.Height), borderColor, actualBorderWidth, ButtonBorderStyle.Solid,
borderColor, actualBorderWidth, ButtonBorderStyle.Solid, borderColor, actualBorderWidth, ButtonBorderStyle.Solid,
borderColor, actualBorderWidth, ButtonBorderStyle.Solid);
}
return;
}
base.WndProc(ref m);
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.FillRectangle(new SolidBrush(BackColor), ClientRectangle);
e.Graphics.TranslateTransform(AutoScrollPosition.X, AutoScrollPosition.Y);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
var offsetX = (AutoScrollPosition.X*-1)/_tileWidth;
var offsetY = (AutoScrollPosition.Y*-1)/_tileHeight;
var visibleX = Width/_tileWidth + 2;
var visibleY = Height/_tileHeight + 2;
var x = Math.Min(visibleX + offsetX, _tilesX);
var y = Math.Min(visibleY + offsetY, _tilesY);
for (var i = offsetX; i < x; i++)
{
for (var j = offsetY; j < y; j++)
{
e.Graphics.FillRectangle(Brushes.Beige, new Rectangle(i*_tileWidth, j*_tileHeight, _tileWidth, _tileHeight));
e.Graphics.DrawString(string.Format("{0}:{1}", i, j), Font, Brushes.Black, new Rectangle(i*_tileWidth, j*_tileHeight, _tileWidth, _tileHeight));
}
}
using (var p = new Pen(Color.Black))
{
for (var i = offsetX + 1; i < x; i++)
{
e.Graphics.DrawLine(p, i*_tileWidth, 0, i*_tileWidth, y*_tileHeight);
}
for (var i = offsetY + 1; i < y; i++)
{
e.Graphics.DrawLine(p, 0, i*_tileHeight, x*_tileWidth, i*_tileHeight);
}
}
e.Graphics.FillRectangle(Brushes.White, AutoScrollPosition.X*-1 + 10, AutoScrollPosition.Y*-1 + 10, 35, 14);
e.Graphics.DrawString("TEST", DefaultFont, new SolidBrush(Color.Red), AutoScrollPosition.X*-1 + 10, AutoScrollPosition.Y*-1 + 10);
e.Graphics.TranslateTransform(AutoScrollPosition.X*-1, AutoScrollPosition.Y*-1);
ControlPaint.DrawBorder(e.Graphics, ClientRectangle, Color.Red, actualBorderWidth, ButtonBorderStyle.None,
Color.Red, actualBorderWidth, ButtonBorderStyle.None, Color.Red, actualBorderWidth, ButtonBorderStyle.Solid,
Color.Red, actualBorderWidth, ButtonBorderStyle.Solid);
}
protected override void OnScroll(ScrollEventArgs e)
{
if (DesignMode)
{
base.OnScroll(e);
return;
}
if (e.Type == ScrollEventType.First)
{
LockWindowUpdate(Handle);
}
else
{
LockWindowUpdate(IntPtr.Zero);
Update();
if (e.Type != ScrollEventType.Last) LockWindowUpdate(Handle);
}
}
protected override void OnMouseWheel(MouseEventArgs e)
{
if (VScroll && (ModifierKeys & Keys.Shift) == Keys.Shift)
{
VScroll = false;
LockWindowUpdate(Handle);
base.OnMouseWheel(e);
LockWindowUpdate(IntPtr.Zero);
Update();
VScroll = true;
}
else
{
LockWindowUpdate(Handle);
base.OnMouseWheel(e);
LockWindowUpdate(IntPtr.Zero);
Update();
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern bool LockWindowUpdate(IntPtr hWnd);
}
Can this flickering be fixed?
I was able to solve my problem by overriding CreateParams:
protected override CreateParams CreateParams
{
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= NativeMethods.WS_EX_CONTROLPARENT;
cp.ExStyle &= (~NativeMethods.WS_EX_CLIENTEDGE);
cp.Style &= (~NativeMethods.WS_BORDER);
cp.Style |= NativeMethods.WS_BORDER;
return cp;
}
}
and here is required NativeMethods class:
internal static class NativeMethods
{
public const int WS_EX_CONTROLPARENT = 0x00010000;
public const int WS_EX_CLIENTEDGE = 0x00000200;
public const int WS_BORDER = 0x00800000;
}
below is the result:
You can simply derive from UserControl. It has built-in support for showing scrollbars and also has built-in support for showing borders.
All of built-in features of UserControl can be added to your control which is derived from ScrollableControl but with some additional try and error effort or taking look at source code of UserControl. But using UserControl class you can simply have those features.
Show Border
To show border, it's enough to set its BorderStyle to FixedSingle to get desired feature:
Show Scrollbars
To gain scroll feature, it's enough to set its AutoScroll to true and also set a suitable AutoScrollMinSize for control. Then when the width or height of the control is less than width or height of given size, the suitable scrollbar will be shown.
Custom Border Color
I also suppose you want to have different border color for the control, then it's enough to override WndProc and handle WM_NCPAINT and draw custom border for the control like this:
In above example, I've used the same technique which I used for Changing BorderColor of TextBox with a small change, here I checked if the BorderStyle equals to FixedSingle the I drew the border with desired color.
Enable the designer to act like a Parent Control at design time
If you want to enable it's designer to be able to drop some controls onto your UserControl, it's enough to decorate it with [Designer(typeof(ParentControlDesigner))]. This way, when you drop your UserControl on form, it can host other controls like a panel control. If you don't like this feature, just don't decorate it with that attribute and it will use Control designer by default which doesn't act like a parent control.

c# RichTextBox Border Color

I'm trying to create a custom RichTextBox with border color, but i have a problem...
My border color not showing
Here's my code :
public partial class AlXRichTextBox : RichTextBox
{
private RichTextBox textBox;
private Color borderColor;
public AlXRichTextBox()
{
InitializeComponent();
}
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Pen p = new Pen(borderColor);
Graphics g = e.Graphics;
int variance = 3;
//g.DrawRectangle(p, new Rectangle(base.Location.X - variance, base.Location.Y - variance, base.Width + variance, base.Height + variance));
ControlPaint.DrawBorder(e.Graphics, base.ClientRectangle, borderColor, ButtonBorderStyle.Solid);
}
private void InitializeComponent()
{
this.textBox = new System.Windows.Forms.RichTextBox();
this.SuspendLayout();
//
// richTextBox1
//
this.textBox.Location = new System.Drawing.Point(0, 0);
this.textBox.Name = "richTextBox1";
this.textBox.Size = new System.Drawing.Size(100, 96);
this.textBox.TabIndex = 0;
this.textBox.Text = "";
this.textBox.Multiline = true;
this.textBox.BorderStyle = BorderStyle.None;
//
// AlXRichTextBox
//
this.Size = new System.Drawing.Size(278, 123);
this.ResumeLayout(false);
}
}
What's problem with this ?
Referring to MSDN article :
Overriding OnPaint will not allow you to modify the appearance of all controls. Those controls that have all of their painting done by Windows (for example, TextBox) never call their OnPaint method, and thus will never use the custom code. Refer to the Help documentation for the particular control you want to modify to see if the OnPaint method is available. For a list of all the Windows Form Controls, see Controls to Use on Windows Forms. If a control does not have OnPaint listed as a member method, you cannot alter its appearance by overriding this method. For more information about custom painting, see Custom Control Painting and Rendering.
However there is a "hack", You can achieve calling the Paint method by calling following code:
private const int WM_PAINT = 15;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && !inhibitPaint)
{
// raise the paint event
using (Graphics graphic = base.CreateGraphics())
OnPaint(new PaintEventArgs(graphic,
base.ClientRectangle));
}
}
private bool inhibitPaint = false;
public bool InhibitPaint
{
set { inhibitPaint = value; }
}
Src: RichTextBox and UserPaint
Other point is that You cannot draw outside of the Rectangle (which is total size of Your RichTB component. So You actually want to provide him with different Coords (smaller inner ones) and You will draw to the outside.
Your class will look like:
public partial class AlXRichTextBox : RichTextBox
{
private Color borderColor = Color.Red;
public Color BorderColor
{
get { return borderColor; }
set { borderColor = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
int variance = 3;
e = new PaintEventArgs(e.Graphics, new Rectangle(e.ClipRectangle.X + variance, e.ClipRectangle.Y + variance, e.ClipRectangle.Width - variance, e.ClipRectangle.Height - variance));
base.OnPaint(e);
Pen p = new Pen(borderColor, variance);
Graphics g = e.Graphics;
g.DrawRectangle(p, new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width, e.ClipRectangle.Height));
}
private const int WM_PAINT = 15;
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
if (m.Msg == WM_PAINT && !inhibitPaint)
{
// raise the paint event
using (Graphics graphic = base.CreateGraphics())
OnPaint(new PaintEventArgs(graphic,
base.ClientRectangle));
}
}
private bool inhibitPaint = false;
public bool InhibitPaint
{
set { inhibitPaint = value; }
}
}
IMPORTANT
As it is not expected for this control to be changed by Paint, You will get "not nice" behavior in regards to the drawing changes like border, new elements etc.. If You would like to use such element, consider using WPF - Windows Presentation Foundation. They are much more nicer to templating the items and modifying design.
A little late answer, but I was on same path as you these days and It got me to this solution, It works for me:
using System;
using System.Drawing;
using System.Windows.Forms;
public class MyRichTextBox : RichTextBox
{
private const UInt32 WM_PAINT = 0x000F;
private const UInt32 WM_USER = 0x0400;
private const UInt32 EM_SETBKGNDCOLOR = (WM_USER + 67);
private const UInt32 WM_KILLFOCUS = 0x0008;
public MyRichTextBox()
{
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
}
protected override void WndProc(ref System.Windows.Forms.Message m)
{
base.WndProc(ref m);
Graphics g = Graphics.FromHwnd(Handle);
Rectangle bounds = new Rectangle(0, 0, Width - 1, Height - 1);
Pen p = new Pen(SystemColors.Highlight, 3);
if (m.Msg == WM_PAINT)
{
if (this.Enabled == true)
{
if (this.Focused)
{
g.DrawRectangle(p, bounds);
}
else
{
g.DrawRectangle(SystemPens.ControlDark, bounds);
}
}
else
{
g.FillRectangle(Brushes.White, bounds);
g.DrawRectangle(SystemPens.Control, bounds);
}
}
if (m.Msg == EM_SETBKGNDCOLOR) //color disabled background
{
Invalidate();
}
if (m.Msg == WM_KILLFOCUS) //set border back to normal on lost focus
{
Invalidate();
}
}
}
This Rich Textbox changes 3 border colors - enabled, focused and disabled with disabled background. As you see the code is simple and short. The only trick is to overide KILL_FOCUS and EM_SETBKGNDCOLOR messages (this one is for changing disabled background), and RichTextbox should be BorderStyle=None. Cheers !

How to make Glass Button ignore form's gradient?

There's some really great code for a glass button here: http://www.lukesw.net/articles/GlassButton.aspx
The only trouble I have with this button is that if I apply a gradient to my forms it affects the color of the button so that it's not quite what I chose at design time. I don't know whether it's the code I'm using to apply the form gradient that's causing this or if the button is not totally opaque or what. I tried fooling around with the button code a bit but didn't get anywhere. You can get the code for the button at the link I posted above. Below is the code I'm using for my form gradient which is located in the form itself right now:
private Color _Color1 = Color.Gainsboro;
private Color _Color2 = Color.Blue;
private float _ColorAngle = 60f;
public Color Color1
{
get { return _Color1; }
set {
_Color1 = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
public Color Color2
{
get { return _Color2; }
set {
_Color2 = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
public float ColorAngle
{
get { return _ColorAngle; }
set {
_ColorAngle = value;
this.Invalidate(); // Tell the Form to repaint itself
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
Graphics g = pevent.Graphics;
Rectangle rBackground = new Rectangle(0, 0, this.Width, this.Height);
System.Drawing.Drawing2D.LinearGradientBrush bBackground
= new System.Drawing.Drawing2D.LinearGradientBrush(rBackground,
_Color1, _Color2, _ColorAngle);
g.FillRectangle(bBackground, rBackground);
bBackground.Dispose();
}
Any pointers on how I can get this button to display the same at runtime as it does at design time would be greatly appreciated!
In the DrawButtonBackground method in GlowButton.cs, just change the opacity to fully opaque (255):
#region " content "
using (GraphicsPath bb = CreateRoundRectangle(rect, 2))
{
//int opacity = pressed ? 0xcc : 0x7f;
int opacity = 255;
using (Brush br = new SolidBrush(Color.FromArgb(opacity, backColor)))
{
g.FillPath(br, bb);
}
}
#endregion

Categories

Resources