我遇到了C#WinForms proyect闪烁的问题。
我只是制作了一个SlideButton控件:这是代码:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.ComponentModel.Design;
namespace DELTA.UI.Search
{
[Designer("System.Windows.Forms.Design.ParentControlDesigner,System.Design", typeof(IDesigner))]
public partial class Slide : UserControl
{
public Boolean IsShown
{
get { return button.IsOpen; }
set
{
button.IsOpen = value;
}
}
private int isShownHeight;
public Slide()
{
InitializeComponent();
this.SetStyle(
System.Windows.Forms.ControlStyles.UserPaint |
System.Windows.Forms.ControlStyles.AllPaintingInWmPaint |
System.Windows.Forms.ControlStyles.Opaque |
System.Windows.Forms.ControlStyles.OptimizedDoubleBuffer,
true);
this.DoubleBuffered = true;
this.ResizeRedraw = true;
isShownHeight = this.Height;
this.Height = button.Height;
}
private void boton_MouseEnter(object sender, EventArgs e)
{
button.BackColor = Color.Gray;
button.Cursor = Cursors.Hand;
}
private void boton_MouseLeave(object sender, EventArgs e)
{
button.BackColor = Color.White;
button.Cursor = Cursors.Arrow;
}
private void button_OnSlideStateChangedEvent(bool isOpen)
{
Debug.WriteLine(isOpen);
if (!timerSlide.Enabled)
{
timerSlide.Start();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
using (Brush b = new SolidBrush(this.BackColor))
e.Graphics.FillRectangle(b, 0, 0, this.Width, this.Height);
int rectWidth = this.Width / 10;
e.Graphics.FillRectangle(Brushes.LightGray, this.Width / 2 - rectWidth / 2, this.Height - 3, rectWidth, 3);
}
private void timerSlide_Tick(object sender, EventArgs e)
{
if (IsShown && this.Height + button.Height < isShownHeight)
{
int crecimiento = (isShownHeight - button.Height) / 35;
this.Height += this.Height + crecimiento >= isShownHeight ? isShownHeight - this.Height : crecimiento;
}
else if (!IsShown && this.Height > button.Height)
{
int decrecimiento = (isShownHeight - button.Height) / 35;
this.Height -= this.Height - decrecimiento <= button.Height ? this.Height - button.Height : decrecimiento;
}
else
{
timerSlide.Stop();
}
}
private void Slide_Resize(object sender, EventArgs e)
{
//this.Invalidate(new Rectangle(0, this.Height - 12, this.Width, 12));
}
}
}
正如您所看到的,我所做的唯一油漆操作是控件底部的小型直立喷漆。这些控件只包含一个带有isOpen标志的自定义按钮,该标志在单击时会发生更改并触发OnSlideStateChangedEvent事件。按钮的代码是:
using DELTA.Util;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DELTA.UI.Search
{
class SlideButton : Button
{
private Boolean isOpen = true;
public Boolean IsOpen
{
get { return isOpen; }
set
{
isOpen = value;
/* Refresh the button with the new appearence */
this.Refresh();
/* Call the event */
if (OnSlideStateChangedEvent != null)
OnSlideStateChangedEvent(isOpen);
}
}
public SlideButton()
: base()
{
this.BackColor = Color.White;
if (!DesignMode)
IsOpen = false;
this.DoubleBuffered = true;
}
/// <summary>
/// Event for the Slide
/// </summary>
[Category("ClickCustomEvents")]
[Description("Fired when this is clicked")]
public event OnSlideStateChanged OnSlideStateChangedEvent;
/// <summary>
/// Delegate for the Change of state
/// </summary>
/// <param name="isOpen"></param>
public delegate void OnSlideStateChanged(Boolean isOpen);
/// <summary>
/// Override to avoid the default OnClick
/// </summary>
/// <param name="e"></param>
protected override void OnClick(EventArgs e)
{
IsOpen = !isOpen;
}
protected override void OnPaint(PaintEventArgs e)
{
// TODO Use the isOpen value to paint it with a filled rectagle or 2 borders
/* SETTINGS -> for open/close states of the button */
Color topColor = Color.LightGray;
Color otherSidesColor = Color.LightGray;
Color backgroud = Color.LightGray;
SingletonImages arrow = SingletonImages.ARROW_DOWN;
Rectangle arrowPosition = new Rectangle(this.Width - 30, this.Height - 26, 20, 20);
if (isOpen)
{
topColor = Color.LightGray;
otherSidesColor = Color.Transparent;
backgroud = Color.White;
arrow = SingletonImages.ARROW_UP;
}
/* PAINT ZONE */
/* Background */
using (SolidBrush brush = new SolidBrush(backgroud))
e.Graphics.FillRectangle(brush, new Rectangle(0, 0, this.Width, this.Height));
/* Border */
ControlPaint.DrawBorder(e.Graphics, this.ClientRectangle,
otherSidesColor, 2, ButtonBorderStyle.Solid,
topColor, 2, ButtonBorderStyle.Solid,
otherSidesColor, 2, ButtonBorderStyle.Solid,
otherSidesColor, 2, ButtonBorderStyle.Solid);
/* Text -> Padding = 5 (This can be changed to use the padding property of the control if need) */
e.Graphics.DrawString(this.Text, this.Font, Brushes.Black, new Point(10, 8));
/* Arrow */
e.Graphics.DrawImage(arrow.Image, arrowPosition);
}
}
}
SingletonImages只是一个“枚举”来保存图像,以便只有一个实例。
我将SlideButton类的DoubleBuffered属性更改为true,但这是不必要的,因为SlideButton没有flickr。闪烁的是Slide类。如果您需要更多信息,请询问您的需求。有提示吗?
答案 0 :(得分:1)
有一天我也遇到了这个问题。最简单(也许不是最优雅)的解决方案是删除OnPaintBackground()
并将其添加到普通OnPaint()
方法中,因为否则每次控件失效时背景都会绘制到最后一个Gfx上导致闪烁:
public ctor()
{
// this does just work with OptimizedDoubleBuffer set to true
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
}
protected override void OnPaintBackground(PaintEventArgs e)
{
// do NOT paint the background here but in OnPaint() to prevent flickering!
//base.OnPaintBackground(e);
}
protected override void OnPaint(PaintEventArgs e)
{
// do the background and the base stuff first (if required)
base.OnPaintBackground(e);
base.OnPaint(e);
// ... custom paint code goes here ...
}
你可以尝试一下,祝你好运。