You can try the standby solutions., like wrapping your call to update the item with
BeginUpdate();
//my update... and
EndUpdate();
... If that doesn't work, you can try changing your Form.DoubleBuffer property to true.
this.DoubleBuffer = true;
But that still may not work. You can even go and find the topics on ListView flicker. The ListView discusson on the web gets to the heart of the issue. The window is erasing the background when it doesn't need to. The solution for ListView is to derive a new class from ListView, set a few ControlStyles and then override the OnNotifyMessage() member.
But that doesn't solve it for ListBox. The solution below, draws upon the ListView solution, and then adds to it something posted by Niel B on EggHeadCafe. Thank you.
Like with ListView, the solution involves Deriving a new ListBox of your own and replacing your existing ListBox with it. Copy the code below into your project Form1.cs (or where ever) and then go to your form and replace references to ListBox with FlickerFreeListBox. You should see the FlickerFreeListBox in your controls tool box, so you can also just drop it on your forms. Since it overrides OnPaint() and must have OnDrawItem() called, the DrawMode is automatically set to OwnerDrawnFixed. If you need something else you will have to experiment.
But enough of all the chatter. Where's the code, right? Here you go.
internal class FlickerFreeListBox : System.Windows.Forms.ListBox
{
public FlickerFreeListBox()
{
this.SetStyle(
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.ResizeRedraw |
ControlStyles.UserPaint,
true);
this.DrawMode = DrawMode.OwnerDrawFixed;
}
protected override void OnDrawItem(DrawItemEventArgs e)
{
if (this.Items.Count > 0)
{
e.DrawBackground();
e.Graphics.DrawString(this.Items[e.Index].ToString(), e.Font, new SolidBrush(this.ForeColor), new PointF(e.Bounds.X, e.Bounds.Y));
}
base.OnDrawItem(e);
}
protected override void OnPaint(PaintEventArgs e)
{
Region iRegion = new Region(e.ClipRectangle);
e.Graphics.FillRegion(new SolidBrush(this.BackColor), iRegion);
if (this.Items.Count > 0)
{
for (int i = 0; i < this.Items.Count; ++i)
{
System.Drawing.Rectangle irect = this.GetItemRectangle(i);
if (e.ClipRectangle.IntersectsWith(irect))
{
if ((this.SelectionMode == SelectionMode.One && this.SelectedIndex == i)
|| (this.SelectionMode == SelectionMode.MultiSimple && this.SelectedIndices.Contains(i))
|| (this.SelectionMode == SelectionMode.MultiExtended && this.SelectedIndices.Contains(i)))
{
OnDrawItem(new DrawItemEventArgs(e.Graphics, this.Font,
irect, i,
DrawItemState.Selected, this.ForeColor,
this.BackColor));
}
else
{
OnDrawItem(new DrawItemEventArgs(e.Graphics, this.Font,
irect, i,
DrawItemState.Default, this.ForeColor,
this.BackColor));
}
iRegion.Complement(irect);
}
}
}
base.OnPaint(e);
}
}
Update: September 24, 2008
Many of those who are having flicker problems with the ListBox are having them because they are programmatically updating the control. By that, I mean that the flicker issue is most pronounced when the program rather than the user input (mouse click, keyboard) results in an update to the ListBox. This programmatic control might be in the form of a timer handler, or a background thread, or the like. For that reason, I've decided to update this page to provide an easy reference to my articles covering multi-threading, synchronization, and timers. I hope you find these of value...
Timers Are A Changin' | The first in my series of articles on "timers". |
Locked-Up | An article on understanding and avoiding dead-lock. |
Thread Syncrohinzed Queue | An article explaining how to make a synchronized queue. |
Threading with .NET ThreadPool | The first in a series of articles on multi-threading using the ThreadPool. |
A Simple TaskQueue | An article and source code on an easy to use task sequencer that works in a different thread. |
Không có nhận xét nào:
Đăng nhận xét