Transparent panel does not render scrollbar correctly - c#

I wanted my panel to be truly transparent, so I followed the instructions on this article:
https://web.archive.org/web/20121226091810/http://www.bobpowell.net/transcontrols.htm
However, I've forced my panel to always show the Vertical scroll bar. It initially is not rendered unless I hover my mouse cursor over it, at which point it begins to appear. What more can be added to the above article to ensure that my panel's scrollbars are always visible, other than setting VerticalScroll.Visible to true?
Here is what I have so far for my custom Panel class. This is using C# .NET 4.0 in Visual Studio 2010:
public class SkinnedList : Panel
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return cp;
}
}
public SkinnedList()
{
AdjustFormScrollbars( true );
}
public new void AdjustFormScrollbars( bool visible )
{
VerticalScroll.Visible = true;
HorizontalScroll.Visible = false;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// Do not render background
}
protected void InvalidateEx()
{
if( Parent != null )
{
Rectangle rc = new Rectangle( Location, Size );
Parent.Invalidate( rc, true );
}
}
}

The InvalidateEx() method isn't correct, you need to map the rectangle from panel coordinates to parent coordinates. Like this:
protected void InvalidateEx() {
if (Parent != null) {
Rectangle rc = new Rectangle(0, 0, this.ClientSize.Width - SystemInformation.VerticalScrollBarWidth, this.ClientSize.Height);
rc = this.RectangleToScreen(rc);
rc = Parent.RectangleToClient(rc);
Parent.Invalidate(rc, false);
}
}
The best way to get the scroll bar is to use the AutoScrollMinSize property:
public SkinnedList() {
this.AutoScroll = true;
this.AutoScrollMinSize = new Size(0, 1000);
this.Scroll += delegate { this.InvalidateEx(); };
}
This should fix your problems, except one. You'll notice the effect of the "Show window content while dragging" system option. It is best described as 'doing the pogo'. No fix for this, you cannot reasonably turn the system option off. This just can't work well.

That's the window style you picked. The control is transparent, meaning if not active it should blend in to the background, and only be interactive when needed.
Some suggestions, I don't know if any of them will work for your case:
Nest your transparent Panel in a normal Panel, and have the transparent one AutoSize itself to fit its contents. Then, the scrollbars will be on the containing Panel and will scroll the autosized, transparent Panel. This keeps the scrollbars always visible as needed, but may spoil your transparent effect.
Put your transparent Panel in a UserControl that has navigation buttons (up, down, pageup, pagedown, etc) that will trigger events on the transparent Panel (Scroll is the big one). This will require your transparent Panel to have handlers for the button click events, in which it will call its own OnScroll() method. This won't look like a standard scrollbar, and you won't be able to click and drag (unless you use a slider), but you can get around easily enough.

Related

How to make label's background color transparent? [duplicate]

Why can't I set the BackColor of a Label to Transparent? I have done it before, but now it just don't want to...
I created a new UserControl, added a progressbar and a label to it. When I set the BackColor of the label to transparent it is still gray =/ Why is this?
What I wanted was to have the label on top of the progressbar so that its text was "in" the progressbar...
Add a new class to your project and post the code shown below. Build. Drop the new control from the top of the toolbox onto your form.
using System;
using System.Windows.Forms;
public class TransparentLabel : Label {
public TransparentLabel() {
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams {
get {
CreateParams parms = base.CreateParams;
parms.ExStyle |= 0x20; // Turn on WS_EX_TRANSPARENT
return parms;
}
}
}
WinForms doesn't really support transparent controls, but you can make a transparent control yourself. See my answer here.
In your case you should probably subclass the progress bar and override the OnPaint method to draw a text on the progress bar.
Most simple solution is following:
Set background color to transparency either in visual editor or in constructor of your form:
this.label1.BackColor = System.Drawing.Color.Transparent;
Set Parent property of your label to control that you want to be visible behind the text. This can be done in form constructor or in Load method:
this.label1.Parent = progressBar1;
Its true that this is not true transparency as in DirectX. The result you see on display is composed only from two layers. You cant sum up more than two layers with this approach (each layer having its own transparency defined by alpha parameter). But its suitable for many practical situations you can encounter in Winforms programming.
Use a LinkLabel not a normal Label
private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel)
{
this.MakeTransparentLabel(LinkLabel, Color.White);
}
private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel, Color ForeColor)
{
LinkLabel.ForeColor = ForeColor;
LinkLabel.LinkColor = ForeColor;
LinkLabel.VisitedLinkColor = ForeColor;
LinkLabel.ActiveLinkColor = ForeColor;
LinkLabel.DisabledLinkColor = ForeColor;
LinkLabel.LinkArea = new LinkArea(0, 0);
LinkLabel.LinkBehavior = LinkBehavior.NeverUnderline;
LinkLabel.Cursor = Cursors.Arrow;
LinkLabel.BackColor = Color.Transparent;
}
private void SetTransparentLabelText(System.Windows.Forms.LinkLabel LinkLabel, string Text)
{
if (string.IsNullOrEmpty(Text)) { LinkLabel.Text = " "; return; }
LinkLabel.Text = Text;
}
This is a very simple solution and works great:
public class MyLabel : Label
{
private bool fTransparent = false;
public bool Transparent
{
get { return fTransparent; }
set { fTransparent = value; }
}
public MyLabel() : base()
{
}
protected override CreateParams CreateParams
{
get
{
if (fTransparent)
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
else return base.CreateParams;
}
}
protected override void WndProc(ref Message m)
{
if (fTransparent)
{
if (m.Msg != 0x14 /*WM_ERASEBKGND*/ && m.Msg != 0x0F /*WM_PAINT*/)
base.WndProc(ref m);
else
{
if (m.Msg == 0x0F) // WM_PAINT
base.OnPaint(new PaintEventArgs(Graphics.FromHwnd(Handle), ClientRectangle));
DefWndProc(ref m);
}
}
else base.WndProc(ref m);
}
}
When label backcolor is transparent, then label only takes picture of its underlying control the first time when it is created, after that label backcolor is constant. And each time when label repaints itself, it repaints to that fixed color or pattern.
Overriding CreateParams affects on how window for control will be created, this enables real transparency.
Overriding WndProc you control which messages should be passed to base class. We must filtrate WM_ERASEBKGND and WM_PAINT, but we also have to trigger paint event.
If you want to focus on designing your windows application, I suggest you use WPF.
Making controles transparent in WPF is very easy.
<TextBox Width="200" Height="40" Opacity="0.5"/>
Here is a transparent control I wrote a while ago which displays rotated text. Most of the code comes from here, though IIRC I had to make a few tweaks to get it to work.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
namespace MyNamespace
{
public partial class RotatedText : UserControl
{
private readonly Timer _invalidationTimer;
private const int WS_EX_TRANSPARENT = 0x00000020;
public RotatedText()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
InitializeComponent();
_invalidationTimer = new Timer {Interval = 500, Enabled = true};
_invalidationTimer.Tick += TickHandler;
}
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Appearance")]
[Description("Text which appears in control")]
public string Text { get; set; }
#region Transparent background
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
private void TickHandler(object sender, EventArgs e)
{
InvalidateEx();
}
private void InvalidateEx()
{
if (Parent != null)
Parent.Invalidate(Bounds, false);
else
Invalidate();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//Intentionally do nothing - stops background from drawing
//base.OnPaintBackground(e);
}
#endregion
//Rotate text and draw
protected override void OnPaint(PaintEventArgs e)
{
double angleRadians = Math.Atan2(Height, Width);
float angleDegrees = -1*(float) (angleRadians*180/Math.PI);
angleDegrees *= 0.9f;
e.Graphics.RotateTransform(angleDegrees, MatrixOrder.Append);
e.Graphics.TranslateTransform(20, Height - 75, MatrixOrder.Append);
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
Font font = new Font("Ariel", 50);
e.Graphics.DrawString(Text, font, Brushes.Gray, 1, 2); //Shadow
e.Graphics.DrawString(Text, font, Brushes.Red, 0, 0);
}
}
}
So as the comment to my previous answer stated, Control is the default behaviour, and is what I remembered as being Transparent.
Anyway, have you tried setting the background property of your UserControl, or the container your label is in (Panel, Form, whatever?), your label should reflect that color :)
Old Answer:
Its been a while since I did winforms programming, but as I recall labels are transparent per default? thus its only the text that gets an actual color and the bacground color mimics whatever is behind it :)
It is possible to do exactly what you want to achieve. It just takes a little time to play with controls. It is possible to create a Label control with transparent background, and place it on top of Progressbar control.
Check my answer to another SO question.
as to an explanation for your problem, windows doesn't do transparency for background controls like you'd expect-i'm guessing the gray background is actually the form's surface. whatever controls are drawn between the form surface and your label are ignored.
Select BackColor, go the Web tab, and select Transparent. Generates the following.
this.label1.BackColor = System.Drawing.Color.Transparent;

Opaque panel, over the top of other controls on form, some controls are drawing over it thought?

public class TransparentPanel : Panel
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//base.OnPaintBackground(e);
//e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(200, 0, 0, 0)), this.Bounds);
Color bk = Color.FromArgb(200, this.BackColor);
e.Graphics.FillRectangle(new SolidBrush(bk), e.ClipRectangle);
}
}
Ive applied this panel to a form.
Underneath i have other controls on the form, some seem to overdraw this new panel, even though the panel is put on the form.controls and my other custom controls are put on another panel that is then put on the form.controls. do I need to do anything specific in my custom controls to allow drawing over the top?
Try the .BringToFront() method on the panel, or the .SendToBack() on the controls that are over your panel.
See MSDN Documentation.
Usually, when you add a new control, its added in front of every other control of that parent.

Custom ListBox with transparent backcolor issue

I created a custom multiline ListBox control inherited from ListBox. In the form, the ListBox position is above a WPF rounded and transparent panel hosted in an ElementHost. Now, what I want, is that ListBox backcolor to be transparent. Obviously, this is not allowed in Winforms, a ListBox cant be transparent. Then, I have tried some things, but there is always an issue.
What I want to achieve is this:
As you can see, this works perfectly, but actually I´m having two problems.
The first I get is when I select an item. The letters became pretty ugly. Just compare the next image with the first one. You can see all of them looks ugly because all of them were selected.
The second problem I have, is when I scroll down/up the ListBox. The transparent color just dissapears and I get a black color.
I remember getting this issue with a scrollable panel in a Form. The panel was transparent and the way to solve it was to call Invalidate() method in the panel Scroll event. But I don´t have that event in the ListBox.
Also, I want to hide the scrollbar but to be scrollable.
I attach the CustomListBox code so you can see what I have done. You are free to take it if you want a simple multiline ListBox too.
Just in case, the way that I used to set the ListBox to transparent, was by overriding CreateParams.
public class MultiLineListBox : System.Windows.Forms.ListBox
{
public MultiLineListBox()
{
this.DrawMode = DrawMode.OwnerDrawVariable;
this.ScrollAlwaysVisible = true;
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT
return cp;
}
}
protected override void OnMeasureItem(MeasureItemEventArgs e)
{
if(Site!=null)
return;
if(e.Index > -1)
{
string s = Items[e.Index].ToString();
SizeF sf = e.Graphics.MeasureString(s,Font,Width);
int htex = (e.Index==0) ? 15 : 10;
e.ItemHeight = (int)sf.Height + htex;
e.ItemWidth = Width;
}
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if(Site!=null)
return;
if(e.Index > -1)
{
string s = Items[e.Index].ToString();
if((e.State & DrawItemState.Focus)==0)
{
e.Graphics.DrawString(s,Font,new SolidBrush(Color.White),e.Bounds);
e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 26, 36, 41)),e.Bounds);
}
else
{
e.Graphics.DrawRectangle(new Pen(Color.FromArgb(255, 0, 185, 57)), e.Bounds);
//e.Graphics.DrawString(s,Font,new SolidBrush(Color.FromArgb(255, 0, 161, 47)),e.Bounds);
}
}
}
}
Oh, I almost forget. I tried overriding the OnPaintBackGround(), it worked by setting SetStyle to userPaint. But it was even more undesirable, because I was not just having the same problems as the other solution, but also the text was not showed, so, I sticked to the first solution.
Hope somebody can help me out!
You could try this...
protected override void OnPaintBackground(PaintEventArgs pevent)
{
IntPtr hdc = pevent.Graphics.GetHdc();
Rectangle rect = this.ClientRectangle;
NativeMethods.DrawThemeParentBackground(this.Handle, hdc, ref rect);
pevent.Graphics.ReleaseHdc(hdc);
}
internal static class NativeMethods
{
[DllImport("uxtheme", ExactSpelling = true)]
public extern static Int32 DrawThemeParentBackground(IntPtr hWnd, IntPtr hdc, ref Rectangle pRect);
}
Its worked for me when I've needed to paint a transparent background color for a control that did not support it. I used it with a TabControl.

UserControl not rendering within FlowLayoutPanel when dock changed

When I add my UserControls to a FlowLayoutPanel, they display properly. When I change the Dock or Anchor properties on the UserControls before adding them, they are still added but do not render.
According to "How to: Anchor and Dock Child Controls" this should be possible.
I can tell that the controls are added (despite not drawing) because adding enough of them causes a vertical scrollbar to appear.
Setting the "Dock" property of the UserControls to "Left" or "None" will cause them to render, but none of the other options.
Setting the "Anchor" property on the UserControls to anything but Top | Left does not render.
Setting the dock before or after adding the control makes no difference (Add, Dock vs. Dock, Add).
The FlowLayoutPanel is itself is docked (Fill), has FlowDirection set to TopDown, has WrapContents set to false, has AutoScroll set to true, and is otherwise default.
I am using .NET 3.5.
In answer to a comment, the two commented lines are the locations I tried to change the dock. The second spot definitely makes more sense, but I tried the other because it couldn't hurt.
public void CreateObjectControl( object o )
{
ObjectControl oc = new ObjectControl();
oc.MyObject = o;
//This was a spot I mentioned:
//oc.Dock = DockStyle.Fill;
ObjectDictionary.Add( o, oc );
flowLayoutPanel1.Controls.Add( oc );
//This is the other spot I mentioned:
oc.Dock = DockStyle.Fill;
}
try using SuspendLayout and Resumelayout function for the controls before making any amendments which need rendering for proper viewing.
You could see the code from Designer.cs for that particular control
Syntax
control.SuspendLayout();
{Your code for designer amendments}
control.resumeaLayout();
I think I may have found a workaround (read: dirty trick) ... this answer helped to point me in the right direction. Here's an excerpt from the MS article that you also linked to:
For vertical flow directions, the FlowLayoutPanel control calculates the width of an implied column from the widest child control in the column. All other controls in this column with Anchor or Dock properties are aligned or stretched to fit this implied column.
The behavior works in a similar way for horizontal flow directions. The FlowLayoutPanel control calculates the height of an implied row from the tallest child control in the row, and all docked or anchored child controls in this row are aligned or sized to fit the implied row.
This page does not specifically mention that you can't Dock/Anchor the tallest/widest control. But as this control defines the layout behaviour of the FlowLayoutPanel, and thus influences the way all other sibling controls are displayed, it is well possible that Dock and Anchor don't work properly for that 'master control'. Even though I can't find any official documentation regarding that, I believe it to be the case.
So, which options do we have? At runtime, we could add a panel control of height 0 and width of the FlowLayoutPanel client area before you add your usercontrol. You can even set that panel's visibility to false. Subscribing to some Resize/Layout events of the FlowLayoutPanel to keep that panel's size will to the trick. But this does not play nicely at design time. The events won't fire and thus you can't really design the surface the way you want it to look.
I'd prefer a solution that "just works" at design time as well. So, here's an attempt at an "invisible" control that I put together, to fix the controls resizing to zero width if no other control is present. Dropping this as first control onto the FlowLayoutPanel at design time seems to provide the desired effect, and any control subsequently placed on the FlowLayoutPanel is anchorable to the right without shrinking to zero width. The only problem is that, once this invisible control is there, it seems I can't remove it anymore via the IDE. It probably needs some special treatment using a ControlDesigner to achieve that. It can still be removed in the form's designer code though.
This control, once placed onto the FlowLayoutPanel, will listen for resize events of it's parent control, and resize itself according to the ClientSize of the parent control. Use with caution, as this may contain pitfalls that didn't occur to me during the few hours I played with this. For example, I didn't try placing controls that were wider than the FlowLayoutPanel's client area.
As a side note, what will still fail is trying to anchor to the bottom, but that wasn't part of the question ;-)
using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
namespace ControlTest
{
public sealed class InvisibleControl : Control
{
public InvisibleControl()
{
TabStop = false;
}
#region public interface
// Reduce the temptation ...
public new AnchorStyles Anchor
{
get { return base.Anchor; }
set { base.Anchor = AnchorStyles.None; }
}
public new DockStyle Dock
{
get { return base.Dock; }
set { base.Dock = DockStyle.None; }
}
// We don't ever want to move away from (0,0)
public new Point Location
{
get { return base.Location; }
set { base.Location = Point.Empty; }
}
// Horizontal or vertical orientation?
private Orientation _orientation = Orientation.Horizontal;
[DefaultValue(typeof(Orientation), "Horizontal")]
public Orientation Orientation
{
get { return _orientation; }
set
{
if (_orientation == value) return;
_orientation = value;
ChangeSize();
}
}
#endregion
#region overrides of default behaviour
// We don't want any margin around us
protected override Padding DefaultMargin => Padding.Empty;
// Clean up parent references
protected override void Dispose(bool disposing)
{
if (disposing)
SetParent(null);
base.Dispose(disposing);
}
// This seems to be needed for IDE support, as OnParentChanged does not seem
// to fire if the control is dropped onto a surface for the first time
protected override void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
ChangeSize();
}
// Make sure we don't inadvertantly paint anything
protected override void OnPaint(PaintEventArgs e) { }
protected override void OnPaintBackground(PaintEventArgs pevent) { }
// If the parent changes, we need to:
// A) Unsubscribe from the previous parent's Resize event, if applicable
// B) Subscribe to the new parent's Resize event
// C) Resize our control according to the new parent dimensions
protected override void OnParentChanged(EventArgs e)
{
base.OnParentChanged(e);
// Perform A+B
SetParent(Parent);
// Perform C
ChangeSize();
}
// We don't really want to be resized, so deal with it
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
ChangeSize();
}
#endregion
#region private stuff
// Make this a default handler signature with optional params, so that this can
// directly subscribe to the parent resize event, but also be called without parameters
private void ChangeSize(object sender = null, EventArgs e = null)
{
Rectangle client = Parent?.ClientRectangle ?? new Rectangle(0, 0, 10, 10);
Size proposedSize = _orientation == Orientation.Horizontal
? new Size(client.Width, 0)
: new Size(0, client.Height);
if (!Size.Equals(proposedSize)) Size = proposedSize;
}
// Handles reparenting
private Control boundParent;
private void SetParent(Control parent)
{
if (boundParent != null)
boundParent.Resize -= ChangeSize;
boundParent = parent;
if (boundParent != null)
boundParent.Resize += ChangeSize;
}
#endregion
}
}

Reasons for why a WinForms label does not want to be transparent?

Why can't I set the BackColor of a Label to Transparent? I have done it before, but now it just don't want to...
I created a new UserControl, added a progressbar and a label to it. When I set the BackColor of the label to transparent it is still gray =/ Why is this?
What I wanted was to have the label on top of the progressbar so that its text was "in" the progressbar...
Add a new class to your project and post the code shown below. Build. Drop the new control from the top of the toolbox onto your form.
using System;
using System.Windows.Forms;
public class TransparentLabel : Label {
public TransparentLabel() {
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
}
protected override CreateParams CreateParams {
get {
CreateParams parms = base.CreateParams;
parms.ExStyle |= 0x20; // Turn on WS_EX_TRANSPARENT
return parms;
}
}
}
WinForms doesn't really support transparent controls, but you can make a transparent control yourself. See my answer here.
In your case you should probably subclass the progress bar and override the OnPaint method to draw a text on the progress bar.
Most simple solution is following:
Set background color to transparency either in visual editor or in constructor of your form:
this.label1.BackColor = System.Drawing.Color.Transparent;
Set Parent property of your label to control that you want to be visible behind the text. This can be done in form constructor or in Load method:
this.label1.Parent = progressBar1;
Its true that this is not true transparency as in DirectX. The result you see on display is composed only from two layers. You cant sum up more than two layers with this approach (each layer having its own transparency defined by alpha parameter). But its suitable for many practical situations you can encounter in Winforms programming.
Use a LinkLabel not a normal Label
private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel)
{
this.MakeTransparentLabel(LinkLabel, Color.White);
}
private void MakeTransparentLabel(System.Windows.Forms.LinkLabel LinkLabel, Color ForeColor)
{
LinkLabel.ForeColor = ForeColor;
LinkLabel.LinkColor = ForeColor;
LinkLabel.VisitedLinkColor = ForeColor;
LinkLabel.ActiveLinkColor = ForeColor;
LinkLabel.DisabledLinkColor = ForeColor;
LinkLabel.LinkArea = new LinkArea(0, 0);
LinkLabel.LinkBehavior = LinkBehavior.NeverUnderline;
LinkLabel.Cursor = Cursors.Arrow;
LinkLabel.BackColor = Color.Transparent;
}
private void SetTransparentLabelText(System.Windows.Forms.LinkLabel LinkLabel, string Text)
{
if (string.IsNullOrEmpty(Text)) { LinkLabel.Text = " "; return; }
LinkLabel.Text = Text;
}
This is a very simple solution and works great:
public class MyLabel : Label
{
private bool fTransparent = false;
public bool Transparent
{
get { return fTransparent; }
set { fTransparent = value; }
}
public MyLabel() : base()
{
}
protected override CreateParams CreateParams
{
get
{
if (fTransparent)
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
else return base.CreateParams;
}
}
protected override void WndProc(ref Message m)
{
if (fTransparent)
{
if (m.Msg != 0x14 /*WM_ERASEBKGND*/ && m.Msg != 0x0F /*WM_PAINT*/)
base.WndProc(ref m);
else
{
if (m.Msg == 0x0F) // WM_PAINT
base.OnPaint(new PaintEventArgs(Graphics.FromHwnd(Handle), ClientRectangle));
DefWndProc(ref m);
}
}
else base.WndProc(ref m);
}
}
When label backcolor is transparent, then label only takes picture of its underlying control the first time when it is created, after that label backcolor is constant. And each time when label repaints itself, it repaints to that fixed color or pattern.
Overriding CreateParams affects on how window for control will be created, this enables real transparency.
Overriding WndProc you control which messages should be passed to base class. We must filtrate WM_ERASEBKGND and WM_PAINT, but we also have to trigger paint event.
If you want to focus on designing your windows application, I suggest you use WPF.
Making controles transparent in WPF is very easy.
<TextBox Width="200" Height="40" Opacity="0.5"/>
Here is a transparent control I wrote a while ago which displays rotated text. Most of the code comes from here, though IIRC I had to make a few tweaks to get it to work.
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;
namespace MyNamespace
{
public partial class RotatedText : UserControl
{
private readonly Timer _invalidationTimer;
private const int WS_EX_TRANSPARENT = 0x00000020;
public RotatedText()
{
this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
InitializeComponent();
_invalidationTimer = new Timer {Interval = 500, Enabled = true};
_invalidationTimer.Tick += TickHandler;
}
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[Category("Appearance")]
[Description("Text which appears in control")]
public string Text { get; set; }
#region Transparent background
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TRANSPARENT;
return cp;
}
}
private void TickHandler(object sender, EventArgs e)
{
InvalidateEx();
}
private void InvalidateEx()
{
if (Parent != null)
Parent.Invalidate(Bounds, false);
else
Invalidate();
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//Intentionally do nothing - stops background from drawing
//base.OnPaintBackground(e);
}
#endregion
//Rotate text and draw
protected override void OnPaint(PaintEventArgs e)
{
double angleRadians = Math.Atan2(Height, Width);
float angleDegrees = -1*(float) (angleRadians*180/Math.PI);
angleDegrees *= 0.9f;
e.Graphics.RotateTransform(angleDegrees, MatrixOrder.Append);
e.Graphics.TranslateTransform(20, Height - 75, MatrixOrder.Append);
e.Graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
Font font = new Font("Ariel", 50);
e.Graphics.DrawString(Text, font, Brushes.Gray, 1, 2); //Shadow
e.Graphics.DrawString(Text, font, Brushes.Red, 0, 0);
}
}
}
So as the comment to my previous answer stated, Control is the default behaviour, and is what I remembered as being Transparent.
Anyway, have you tried setting the background property of your UserControl, or the container your label is in (Panel, Form, whatever?), your label should reflect that color :)
Old Answer:
Its been a while since I did winforms programming, but as I recall labels are transparent per default? thus its only the text that gets an actual color and the bacground color mimics whatever is behind it :)
It is possible to do exactly what you want to achieve. It just takes a little time to play with controls. It is possible to create a Label control with transparent background, and place it on top of Progressbar control.
Check my answer to another SO question.
as to an explanation for your problem, windows doesn't do transparency for background controls like you'd expect-i'm guessing the gray background is actually the form's surface. whatever controls are drawn between the form surface and your label are ignored.
Select BackColor, go the Web tab, and select Transparent. Generates the following.
this.label1.BackColor = System.Drawing.Color.Transparent;

Categories

Resources