In my WinForm Application, I am needing to layer some images. However, I'm having trouble getting a transparent control to place the image in. I have done some research and came up with the following class:
public class TransparentPicture : PictureBox
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// do nothing
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
}
This seems to work fine until I close Visual Studios and reopen the Solution. Then my controls all disappear in the designer. They show when I run the program, but I need them to show in designer too where I can continue to design my application.
I know this isn't everything I need to do, because these controls are always causing my program to freeze up for a few seconds and stuff.
So my question is..does anybody know where I can find code for a transparent control, or how to fix the one I've thrown together?
Make the TransparentPicture be a regular PictureBox, until an IsTransparent property is set to true.
Set the property to false on design time, and to true in FormLoad event (which will only happen when you actually run the application).
That way, on design time, they will behave as regular picture boxes, but when you run the application, they will become transparent.
public class TransparentPicture : PictureBox
{
public bool IsTransparent { get; set; }
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
if (this.IsTransparent)
{
cp.ExStyle |= 0x20;
}
return cp;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
if (!this.IsTransparent)
{
base.OnPaintBackground(e);
}
}
protected override void OnMove(EventArgs e)
{
if (this.IsTransparent)
{
RecreateHandle();
}
else
{
base.OnMove(e);
}
}
}
Then, on your FormLoad event, you should do:
for (var i = 0; i < this.Controls.Count; i++)
{
var tp = this.Controls[i] as TransparentPicture;
if (tp != null)
{
tp.IsTransparent = true;
}
}
Or if you only have a few:
tp1.IsTransparent = tp2.IsTransparent = tp3.IsTransparent = true;
Related
Is it possible for us to turn WS_EX_COMPOSITED on ONLY when a Panel/Container Control is being scrolled, then turning it off? Having it activated for the whole lifespan of the application, affects every controls surrounding my application, I only need it activated when the Panel it's being scrolled.
Something like that:
private int originalExStyle = -1;
private bool _scrolling = false;
protected override CreateParams CreateParams
{
get
{
if (originalExStyle == -1)
originalExStyle = base.CreateParams.ExStyle;
CreateParams cp = base.CreateParams;
if (_scrolling)
cp.ExStyle |= 0x02000000; // Turn on
else
cp.ExStyle = originalExStyle; // Reset to original state
return cp;
}
}
protected override void OnScrollBegin(ScrollEventArgs se)
{
base.OnScrollBegin(se);
_scrolling = true;
RecreateHandle();
}
protected override void OnScrollEnd(ScrollEventArgs se)
{
base.OnScrollEnd(se);
_scrolling = false;
RecreateHandle();
}
When I resize the Winform UI (which has lot of child controls), flickering happens.
I used the below code, which is not working for Resize.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style &= ~0x02000000;// Turn off WS_CLIPCHILDREN
return cp;
}
}
Create a Panel which will be the root of all children in your Form, and in your Form.OnResizeBegin() method, call Control.SuspendLayout(); in Form.OnResizeEnd(), call Control.ResumeLayout().
class MainForm: Form {
public MainForm()
{
this.Build();
}
void Build()
{
this.root = new Panel { Dock = DockStyle.Fill };
// create all controls and add them to root
this.Controls.Add( root );
this.ResizeBegin += (obj, args) => this.OnResizeBegin();
this.ResizeEnd += (obj, args) => this.OnResizeEnd();
}
void OnResizeBegin()
{
this.root.SuspendLayout();
}
void OnResizeEnd()
{
this.root.ResumeLayout( true );
}
Panel root;
}
Hope this helps.
I think you should change the ExStyle not the Style to get the double buffered effect
Also you should use |= in stead of &=
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // turn on WS_EX_COMPOSITED
return cp;
}
}
If there are still parts on your form that keep flickering then maybe this post can help
So I'm coding a project that is Plants vs. Zombies made of pure c# using no game engines and here I have a graphic problem.
I need to render a transparent picturebox over another transparent picturebox and I had to define a new control that is really transparent and everything goes fine with the transparency aspect but here is a problem:
Flicker :|
I have so much of them because of the RecreateHandle(); method I use when I change the image of my control to make animations and when it moves to have the real transparency.
Here is my code I wonder if any one could help !
public class TransparentControl : Control
{
private Image _image;
public TransparentControl()
{
SetStyle(ControlStyles.AllPaintingInWmPaint |
ControlStyles.SupportsTransparentBackColor, true);
base.BackColor = Color.FromArgb(0, 0, 0, 0);
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x20;
return cp;
}
}
protected override void OnMove(EventArgs e)
{
//RecreateHandle();
}
protected override void OnPaint(PaintEventArgs e)
{
if (_image != null)
{
e.Graphics.DrawImage(_image, (Width / 2) - (_image.Width / 2), (Height / 2) - (_image.Height / 2));
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
//Do not paint background
}
//Hack
public void Redraw()
{
//RecreateHandle();
}
public Image Image
{
get
{
return _image;
}
set
{
_image = value;
//RecreateHandle();
}
}
}
One way to reduce flickering is to create two different bitmaps. One to draw to, and one to display.
Image BackBuffer;
Image BrontBuffer;
private void RotateImages()
{
lock (this.BackBuffer)
{
var temp = this.BackBuffer;
this.BackBuffer = this.FrontBuffer;
this.FrontBuffer = temp;
}
}
Draw everything into your BackBuffer, then show the FrontBuffer.
Note that you should declare the FrontBuffer with the same width/height values as the BackBuffer, in pretty much exactly the same spot that you declare the BackBuffer.
Use the method RotateImages() immediately after (before should work, too) you display the front buffer.
I've created a transparent label control and the transparency works great. However, I find when I update the control's Text field, the original Text doesn't clear before it paints the new text. So if I change the control's Text field several times, it soon becomes unreadable.
Any clues? Thanks!
public partial class TransLabel : Label
{
public TransLabel()
{
InitializeComponent();
this.SetStyle(ControlStyles.Opaque, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
this.Font = new Font("Franklin Gothic Book", 12f, FontStyle.Regular);
this.ForeColor = Color.White;
this.BackColor = Color.Transparent;
}
public override string Text
{
get
{
return base.Text;
}
set
{
base.Text = value;
this.Invalidate(); // seems to have no effect
this.Refresh(); // seems to have no effect
}
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
//do nothing
}
protected override void OnMove(EventArgs e)
{
RecreateHandle();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle = 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
}
Try changing your Text property to this:
public override string Text {
get {
return base.Text;
}
set {
base.Text = value;
if (this.Parent != null)
this.Parent.Invalidate(this.Bounds, false);
}
}
Since WinForms doesn't have true support for transparency, I think you have to invalidate the parent container.
Also, when inheriting a control, you usually don't have an InitializeComponent() method.
I am creating some always-on-top toasts as forms and when I open them I'd like them not to take away focus from other forms as they open. How can I do this?
Thanks
protected override bool ShowWithoutActivation
{
get
{
return true;
}
}
Override this property in your form code and it should do the trick for you.
It took me a few minutes using Adam's & Aaron's info above, but I finally got it to work for me. The one thing I had to do was make sure the form's Top Most property is set to false. Here is the code I used...
protected override bool ShowWithoutActivation { get { return true; } }
protected override CreateParams CreateParams
{
get
{
//make sure Top Most property on form is set to false
//otherwise this doesn't work
int WS_EX_TOPMOST = 0x00000008;
CreateParams cp = base.CreateParams;
cp.ExStyle |= WS_EX_TOPMOST;
return cp;
}
}