Flickering with transparent panel - c#

I've created a simple program and now i'm in the stages of doing my designing. I've got a multiple Panels which i make visible / invisible to switch between "tabs" (EG. 1 panel for the login screen and 1 panel for the create account screen). Now i've made these panels invisible because i want them just as containers to be able to quickly move around controls and create buttons in.
My problem is that i've set my forms background image to a image i made in photoshop and whenever i switch between panels it flickers, whenever i just use a system color (white,black) this doesn't happen.
Is there any way for me to remove the flickering?
i've tried :
Setting double buffer to true
protected overrideing OnPaint, CreateBackground, and Createparam
my code is extremely basic :
private void btnNewAcc_Click(object sender, EventArgs e)
{
PanelNewAccount.Visible = true;
PanelLogin.Visible = false;
}

Try to setting the form property DoubleBuffered to true, in winforms the flickering usually happens because the GDI+ is trying to draw the control(s) a lot of times so DoubleBuffering you graphics should help in such cases
form.DoubleBuffered = true;

Thanks to Patrick i've solved my problem,
instead of using panels i'm using a TabControl and i assigned the same background to each tab.
Just as easy to add dynamic buttons as well.
Same features as panels but without the flickering.

#region .. Double Buffered function ..
public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
return;
System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
aProp.SetValue(c, true, null);
}
#endregion
#region .. code for Flucuring ..
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
#endregion
Even though i am late but if somebody else is also suffering from the same problem then this code fixed the flickering for me even though i dont know how it works.
I found it here.
Add the above code snippet in your program and in the contructor of your app add this line:
SetDoubleBuffered(YourPanelName);

protected override CreateParams CreateParams {
get {
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
code copy from codeproject solved my problem.

Related

Selecting item in PropertyGrid causes UI flicker

I have designed a WinForms app with a several (nested) TableLayoutPanel containing background images and colors indicating status of hardware components. I added a PropertyGrid to display content of a specific object using the ComponentModel.
Example:
public class MyObject
{
public float Voltage;
[Category("Operation Voltage")]
[Description("Voltage applied")]
[DisplayName("Voltage")]
public float Vop { get => Voltage; }
}
I add the object to a PropertyGrid (the example is nonsense - only for illustration)
MyObject m = new MyObject();
m.Voltage = 1.234;
propertyGrid1.SelectedObject = m;
All works fine so far until I actively select the value in the PropertyGrid the actual value, selecting the category header has no side effect). If I do so, most TableLayoutPanel in my app start to flicker.
The problem is caused by (which I need for other purposes) this method described here:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
Following this article here which describes the issue in my opinion I am supposed to release the "device context". Can anyone point out how to do that in case of a PropertyGrid?

How to avoid screen flickering?

I am making a windows form application and mainly my screen is divided between 3 parts like
===========================================================================
Top panel (it doesn't flicker)
===========================================================================
|| || 'it has a panel & panel contains a table layout,this tabble layout'
|| || 'has a picture box and a label, picture & text of label is'
|| ||'changed on the click of side bar menu' (PROB: this flickers a lot)
||side bar ||==============================================================
||(doesn't ||'this part also has a panel and panel contains different table'
||flicker) ||'layouts and on the click of a menu, related table layout is shown and'
|| ||'some of the parts of table layout are created dynamically.'
|| ||
|| || (PROB: this flickers a lot)
|| ||
i searched a lot and found this solution everywhere and i tried this
public constructor()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.DoubleBuffered = true;
DoubleBuffered = true;
SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.ContainerControl |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor
, true);
}
i also tried this
protected override CreateParams CreateParams
{
get
{
CreateParams handleParam = base.CreateParams;
handleParam.ExStyle |= 0x02000000; // WS_EX_COMPOSITED
return handleParam;
}
}
it changes the whole background of my screen to black color.
but still problem remains the same, can someone tell me how to solve this problem and where i am doing mistake ?
Thanks a lot in advance.
Without more to go on, my gut says that you are either adding a lot of data do those areas or there is a lot of resizing going on.
try this anywhere you update the screen ( adding rows to listviews/boxes/etc ) or resize the screen, or anything else that will cause the screen to redraw.
ex:
public void something_resize(object sender, EventArgs e)
{
try
{
this.SuspendLayout();
// Do your update, add data, redraw, w/e.
// Also add to ListViews and Boxes etc in Batches if you can, not item by item.
}
catch
{
}
finally
{
this.ResumeLayout();
}
}
Its important to put the ResumeLayout() call in the finally block, because if an exception occurs for w/e reason, you want your window to layout, regardless of what you do with the exception.

C# transparent PNG for buttons, panels...how?

I have being searching a lot, seen a few examples but they don't work at least for me. This is what I need: in my application I need to use transparent PNG icons for the toolbars and also for draggable visual objects representations, ie, 72x72 "page" icon which can be dragged around and possibly over all elements in the client area. For the first I was thinking about using a button, set its BackImage to the transparent PNG and put BackColor as "transparent": it won't work, the button always show a solid color behind. As for the panel, the same problem: I can put a transparent PNG as background image but the control never looks "transparent" where the PNG has transparent areas. I think the same with a picturebox and any other control allowing image backgrounds. So I guess, it is really about making a control's background transparent...Any ideas?
I don't care if I need to create some sort of custom "image button" or "image panel" --whatever-- to have truely PNG transparent buttons, panels, etc! Also, please note, it is about PNG transparency, using the alpha channel, not transparent pixels, which at this ages, sucks IMHO for decent GUIs.
Cheers
litium
Ok I found the following code whith works not only for panels but also for buttons and I guess other controls --except PictureBox:
public class TransparentPanel : Panel <==change to Button for instance, and works
{
Timer Wriggler = new Timer();
public TransparentPanel()
{
Wriggler.Tick += new EventHandler(TickHandler);
this.Wriggler.Interval = 500;
this.Wriggler.Enabled = true;
}
protected void TickHandler(object sender, EventArgs e)
{
this.InvalidateEx();
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT
return cp;
}
}
protected void InvalidateEx()
{
if (Parent == null)
{
return;
}
Rectangle rc = new Rectangle(this.Location, this.Size);
Parent.Invalidate(rc, true);
}
protected override void OnPaintBackground(PaintEventArgs pevent)
{
// Do not allow the background to be painted
}
}
Works for me 100%! Doesn't seems to work for PictureBoxes.

How to make a window have taskbar text but no title bar

How can I make my window not have a title bar but appear in the task bar with some descriptive text?
If you set the Form's .Text property then .net gives it a title bar, which I don't want.
this.ControlBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.MinimizeBox = false;
this.ShowInTaskbar = true;
this.Text = "My title for task bar";
I've found a partial solution, to override CreateParams:
protected override System.Windows.Forms.CreateParams CreateParams
{
get
{
System.Windows.Forms.CreateParams cp = base.CreateParams;
cp.Style &= ~0x00C00000; // WS_CAPTION
return cp;
}
}
However this causes my window to be resized as if they have a title bar, ie it's taller than it should be. Is there any good solution to this?
In my case I have a Form with FormBorderStyle = FormBorderStyle.SizableToolWindow and the following CreateParams override did the trick (i.e. I now have a form without caption and without additional margin for the title, but it keeps the title in the task bar):
protected override System.Windows.Forms.CreateParams CreateParams
{
get
{
var parms = base.CreateParams;
parms.Style &= ~0x00C00000; // remove WS_CAPTION
parms.Style |= 0x00040000; // include WS_SIZEBOX
return parms;
}
}
One approach to look into might be to set the FormBorderStyle property of your Form to None (instead of FixedDialog).
The drawback to this approach is that you lose the borders of your window as well as the Titlebar. A result of this is that you lose the form repositioning/resizing logic that you normally get "for free" with Windows Forms; you would need to deal with this by implementing your own form move/resize logic in the form's MouseDown and MouseMove event handlers.
I would also be interested to hear about better solutions.
Just set the border style to None.
this.FormBorderStyle = FormBorderStyle.None;
Once you have removed the borders with the FormBorderStyle, as mentioned already, you can make it draggable fairly easily. I describe this at http://www.blackwasp.co.uk/DraggableBorderless.aspx.

How to double buffer .NET controls on a form?

How can I set the protected DoubleBuffered property of the controls on a form that are suffering from flicker?
Here's a more generic version of Dummy's solution.
We can use reflection to get at the protected DoubleBuffered property, and then it can be set to true.
Note: You should pay your developer taxes and not use double-buffering if the user is running in a terminal services session (e.g. Remote Desktop) This helper method will not turn on double buffering if the person is running in remote desktop.
public static void SetDoubleBuffered(System.Windows.Forms.Control c)
{
//Taxes: Remote Desktop Connection and painting
//http://blogs.msdn.com/oldnewthing/archive/2006/01/03/508694.aspx
if (System.Windows.Forms.SystemInformation.TerminalServerSession)
return;
System.Reflection.PropertyInfo aProp =
typeof(System.Windows.Forms.Control).GetProperty(
"DoubleBuffered",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
aProp.SetValue(c, true, null);
}
Check this thread
Repeating the core of that answer, you can turn on the WS_EX_COMPOSITED style flag on the window to get both the form and all of its controls double-buffered. The style flag is available since XP. It doesn't make painting faster but the entire window is drawn in an off-screen buffer and blitted to the screen in one whack. Making it look instant to the user's eyes without visible painting artifacts. It is not entirely trouble-free, some visual styles renderers can glitch on it, particularly TabControl when its has too many tabs. YMMV.
Paste this code into your form class:
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}
The big difference between this technique and Winform's double-buffering support is that Winform's version only works on one control at at time. You will still see each individual control paint itself. Which can look like a flicker effect as well, particularly if the unpainted control rectangle contrasts badly with the window's background.
System.Reflection.PropertyInfo aProp = typeof(System.Windows.Forms.Control)
.GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
aProp.SetValue(ListView1, true, null);
Ian has some more information about using this on a terminal server.
public void EnableDoubleBuffering()
{
this.SetStyle(ControlStyles.DoubleBuffer |
ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint,
true);
this.UpdateStyles();
}
One way is to extend the specific control you want to double buffer and set the DoubleBuffered property inside the control's ctor.
For instance:
class Foo : Panel
{
public Foo() { DoubleBuffered = true; }
}
nobugz gets the credit for the method in his link, I'm just reposting. Add this override to the Form:
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
This worked best for me, on Windows 7 I was getting large black blocks appearing when I resize a control heavy form. The control now bounce instead! But it's better.
Extension method to turn double buffering on or off for controls
public static class ControlExtentions
{
/// <summary>
/// Turn on or off control double buffering (Dirty hack!)
/// </summary>
/// <param name="control">Control to operate</param>
/// <param name="setting">true to turn on double buffering</param>
public static void MakeDoubleBuffered(this Control control, bool setting)
{
Type controlType = control.GetType();
PropertyInfo pi = controlType.GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
pi.SetValue(control, setting, null);
}
}
Usage (for example how to make DataGridView DoubleBuffered):
DataGridView _grid = new DataGridView();
// ...
_grid.MakeDoubleBuffered(true);
Before you try double buffering, see if SuspendLayout()/ResumeLayout() solve your problem.
This caused me a lot of grief for two days with a third party control until I tracked it down.
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.ExStyle |= 0x02000000;
return cp;
}
}
I recently had a lot of holes (droppings) when re-sizing / redrawing a control containing several other controls.
I tried WS_EX_COMPOSITED and WM_SETREDRAW but nothing worked until I used this:
private void myPanel_SizeChanged(object sender, EventArgs e)
{
Application.DoEvents();
}
Just wanted to pass it on.
vb.net version of this fine solution....:
Protected Overrides ReadOnly Property CreateParams() As CreateParams
Get
Dim cp As CreateParams = MyBase.CreateParams
cp.ExStyle = cp.ExStyle Or &H2000000
Return cp
End Get
End Property
You can also inherit the controls into your own classes, and set the property in there. This method is also nice if you tend to be doing a lot of set up that is the same on all of the controls.
I have found that simply setting the DoubleBuffered setting on the form automatically sets all the properties listed here.
FWIW
building on the work of those who've come before me:
Dummy's Solution, Ian Boyd's Solution, Amo's Solution
here is a version that sets double buffering via SetStyle in PowerShell using reflection
function Set-DoubleBuffered{
<#
.SYNOPSIS
Turns on double buffering for a [System.Windows.Forms.Control] object
.DESCRIPTION
Uses the Non-Public method 'SetStyle' on the control to set the three
style flags recomend for double buffering:
UserPaint
AllPaintingInWmPaint
DoubleBuffer
.INPUTS
[System.Windows.Forms.Control]
.OUTPUTS
None
.COMPONENT
System.Windows.Forms.Control
.FUNCTIONALITY
Set Flag, DoubleBuffering, Graphics
.ROLE
WinForms Developer
.NOTES
Throws an exception when trying to double buffer a control on a terminal
server session becuase doing so will cause lots of data to be sent across
the line
.EXAMPLE
#A simple WinForm that uses double buffering to reduce flicker
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$Pen = [System.Drawing.Pen]::new([System.Drawing.Color]::FromArgb(0xff000000),3)
$Form = New-Object System.Windows.Forms.Form
Set-DoubleBuffered $Form
$Form.Add_Paint({
param(
[object]$sender,
[System.Windows.Forms.PaintEventArgs]$e
)
[System.Windows.Forms.Form]$f = $sender
$g = $e.Graphics
$g.SmoothingMode = 'AntiAlias'
$g.DrawLine($Pen,0,0,$f.Width/2,$f.Height/2)
})
$Form.ShowDialog()
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.control.setstyle?view=net-5.0
.LINK
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.controlstyles?view=net-5.0
#>
param(
[parameter(mandatory=$true,ValueFromPipeline=$true)]
[ValidateScript({$_ -is [System.Windows.Forms.Control]})]
#The WinForms control to set to double buffered
$Control,
[switch]
#Override double buffering on a terminal server session(not recomended)
$Force
)
begin{try{
if([System.Windows.Forms.SystemInformation]::TerminalServerSession -and !$Force){
throw 'Double buffering not set on terminal server session.'
}
$SetStyle = ([System.Windows.Forms.Control]).GetMethod('SetStyle',
[System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
)
$UpdateStyles = ([System.Windows.Forms.Control]).GetMethod('UpdateStyles',
[System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Instance
)
}catch {$PSCmdlet.ThrowTerminatingError($PSItem)}
}process{try{
$SetStyle.Invoke($Control,#(
([System.Windows.Forms.ControlStyles]::UserPaint -bor
[System.Windows.Forms.ControlStyles]::AllPaintingInWmPaint -bor
[System.Windows.Forms.ControlStyles]::DoubleBuffer
),
$true
))
$UpdateStyles.Invoke($Control,#())
}catch {$PSCmdlet.ThrowTerminatingError($PSItem)}}
}

Categories