Overriding DrawItem for ListBox - Unselected items are not redrawn

This is a C # desktop application. The DrawStyle DrawStyle my ListBox set to OwnerDrawFixed .

Problem: I override DrawItem to draw text in different fonts and it works. But when I start resizing the form at run time, the selected element is drawn correctly, but the rest of them are not redrawn, which leads to distortion of the text for unselected elements.

Here is my code:

 private void listDevices_DrawItem(object sender, DrawItemEventArgs e) { e.DrawBackground(); string textDevice = ((ListBox)sender).Items[e.Index].ToString(); e.Graphics.DrawString(textDevice, new Font("Ariel", 15, FontStyle.Bold), new SolidBrush(Color.Black), e.Bounds, StringFormat.GenericDefault); // Figure out where to draw IP StringFormat copy = new StringFormat( StringFormatFlags.NoWrap | StringFormatFlags.MeasureTrailingSpaces ); copy.SetMeasurableCharacterRanges(new CharacterRange[] {new CharacterRange(0, textDevice.Length)}); Region[] regions = e.Graphics.MeasureCharacterRanges( textDevice, new Font("Ariel", 15, FontStyle.Bold), e.Bounds, copy); int width = (int)(regions[0].GetBounds(e.Graphics).Width); Rectangle rect = e.Bounds; rect.X += width; rect.Width -= width; // draw IP e.Graphics.DrawString(" 255.255.255.255", new Font("Courier New", 10), new SolidBrush(Color.DarkBlue), rect, copy); e.DrawFocusRectangle(); } listDevices.Items.Add("Device001"); listDevices.Items.Add("Device002"); 

In addition, the element that is drawn correctly (selected) flickers when the shape is resized. No biggie, but if anyone knows why .... tnx

+4
source share
2 answers

Put the following code in the Resize event:

 private void listDevices_Resize(object sender, EventArgs e) { listDevices.Invalidate(); } 

This should lead to the fact that everything will be redrawn.

To stop flickering, you need double buffering.

To do this, create a new class derived from the ListBox and put the following in the constructor:

 this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); 

Or just paste this into your code file:

 using System.Windows.Forms; namespace Whatever { public class DBListBox : ListBox { public DBListBox(): base() { this.DoubleBuffered = true; // OR // this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true); } } } 

Replace β€œIndependently” with the namespace your project uses, or make it more useful. When compiling AFT, you should be able to add a DBListBox to the form constructor.

+5
source

I reproduce the problem. There are several errors in the code, the font name is "Arial", you should not configure rect.Width, you forgot to call Dispose () on fonts, brushes and areas. But they do not explain the behavior. There is something wrong with the clipping area, which prevents the text from updating correctly. I do not see where this is happening, the state of the Graphics object is fine.

Graphics.DrawString () is a very problematic method, you really should avoid it. All Windows Forms controls, including ListBox, use TextRenderer.DrawText (). This solves the problem when I use it. I know that measuring is more complicated, you can get around this by specifying a fixed offset IP address. It also looks better, they will be located in the column in this way.

It flickers because you are using e.DrawBackground (). This erases the existing text, you draw the text directly on it. I don’t think that double buffering will fix this, you have to draw the whole thing so as not to paint the background. It is difficult if you cannot get the exact size of the text with a large font, a workaround is to first draw a bitmap.

+4
source

Source: https://habr.com/ru/post/1316066/


All Articles