Is it possible to loop through items in a ListBox and highlight or indicate item unavailability somehow by checking a class for a value?
Basically, got a Game class and within stored info whether Game is Available so I need to check this class when looping through the ListBox Items and somehow indicate on the ListBox if GameAvailable = false.
Got to this point and not sure how to carry on:
private void HighlightUnavailable()
{
foreach(string item in listbox_consoles.Items)
{
foreach (Products.Game game in GameService.AllGames())
{
if (item == game.GameName.ToString())
{
if (game.GameAvailable)
{
}
}
}
}
}
Yes that's possible in such a way as:
Bind the ListBox to the GameService.AllGames() which returns I believe a list or an array of the Game objects.
Set the ListBox.DrawMode to DrawMode.OwnerDrawFixed and handle the ListBox.DrawItem event to draw the items according to their GameAvailable properties.
Assuming the controls names are Form1 and listBox1, add in Form1 constructor:
public Form1()
{
InitializeComponent();
//...
listBox1.DrawMode = DrawMode.OwnerDrawFixed;
listBox1.DrawItem += (s, e) => OnListBoxDrawItem(s, e);
listBox1.DataSource = GameService.AllGames();
}
Say you want to display the available games with green and the rest with red foreground colors.
private void OnListBoxDrawItem(object sender, DrawItemEventArgs e)
{
//Comment if you don't need to show the selected item(s)...
e.DrawBackground();
if (e.Index == -1) return;
var game = listBox1.Items[e.Index] as Game;
var foreColor = game.GameAvailable ? Color.Green : Color.Red;
//Pass the listBox1.BackColor instead of the e.BackColor
//if you don't need to show the selection...
TextRenderer.DrawText(e.Graphics, game.GameName, e.Font,
e.Bounds, foreColor, e.BackColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
... or with different background colors:
private void OnListBoxDrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1) return;
var game = listBox1.Items[e.Index] as Game;
var backColor = e.State.HasFlag(DrawItemState.Selected)
? e.BackColor
: game.GameAvailable
? Color.LightGreen
: listBox1.BackColor;
//Or this if you don't need to show the selection ...
//var backColor = game.GameAvailable
// ? Color.LightGreen
// : listBox1.BackColor;
using (var br = new SolidBrush(backColor))
e.Graphics.FillRectangle(br, e.Bounds);
TextRenderer.DrawText(e.Graphics, game.GameName, e.Font,
e.Bounds, Color.Black, backColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
... or with a couple of yes and no images from your resources:
Bitmap YesImage, NoImage;
public Form1()
{
InitializeComponent();
//...
YesImage = Properties.Resources.YesImage;
NoImage = Properties.Resources.NoImage;
listBox1.DrawMode = DrawMode.OwnerDrawFixed;
listBox1.DrawItem += (s, e) => OnListBoxDrawItem(s, e);
listBox1.DataSource = GameService.AllGames();
this.FormClosed += (s, e) => { YesImage.Dispose(); NoImage.Dispose(); };
}
private void OnListBoxDrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == -1) return;
var game = listBox1.Items[e.Index] as Game;
var backColor = e.State.HasFlag(DrawItemState.Selected)
? e.BackColor
: listBox1.BackColor;
var bmp = game.GameAvailable ? YesImage : NoImage;
var rectImage = new Rectangle(
3, e.Bounds.Y + ((e.Bounds.Height - bmp.Height) / 2),
bmp.Width, bmp.Height
);
var rectTxt = new Rectangle(
rectImage.Right + 3, e.Bounds.Y,
e.Bounds.Right - rectImage.Right - 3,
e.Bounds.Height
);
using (var br = new SolidBrush(backColor))
e.Graphics.FillRectangle(br, e.Bounds);
e.Graphics.DrawImage(bmp, rectImage);
TextRenderer.DrawText(e.Graphics, game.GameName, e.Font,
rectTxt, Color.Black, backColor,
TextFormatFlags.Left | TextFormatFlags.VerticalCenter);
}
Related
The idea here is that I redraw the combol "cell" so that it shows the block of colour and text. This is when form displays and it is about to show the dropdown:
After I have selected a colour it does weird:
Now it is all wrong. I have to hover the mouse over the control to render other bits. Just not working right.
My handler:
private void DataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if(e.ColumnIndex == 0 && e.RowIndex > 0)
{
e.PaintBackground(e.ClipBounds, true);
e.PaintContent(e.ClipBounds);
Graphics g = e.Graphics;
Color c = Color.Empty;
string s = "";
Brush br = SystemBrushes.WindowText;
Brush brBack;
Rectangle rDraw;
rDraw = e.ClipBounds;
rDraw.Inflate(-1, -1);
{
brBack = Brushes.White;
g.FillRectangle(brBack, e.ClipBounds);
}
try
{
ComboboxColorItem oColorItem = (ComboboxColorItem)((ComboBox)sender).SelectedItem;
s = oColorItem.ToString();
c = oColorItem.Value;
}
catch
{
s = "red";
c = Color.Red;
}
SolidBrush b = new SolidBrush(c);
Rectangle r = new Rectangle(e.ClipBounds.Left + 5, e.ClipBounds.Top + 3, 10, 10);
g.FillRectangle(b, r);
g.DrawRectangle(Pens.Black, r);
g.DrawString(s, Form.DefaultFont, Brushes.Black, e.ClipBounds.Left + 25, e.ClipBounds.Top + 1);
b.Dispose();
g.Dispose();
e.Handled = true;
}
}
}
Is there something I am missing? Must be.
Update:
I tried this in the CellPainting event:
if(e.ColumnIndex == 0 && e.RowIndex > 0)
{
using (Graphics g = e.Graphics)
{
g.FillRectangle(Brushes.Aqua, e.CellBounds);
}
}
else
{
e.PaintBackground(e.CellBounds, true);
e.PaintContent(e.CellBounds);
}
e.Handled = true;
That improves things in the sense that it does not go as weird. Ofcourse, it is not actually drawing anything. But then it doe snot take long for the left most cells (with the editing symbols) to only show in white. So the mechanics of it are still not right.
Thank you.
If I try it the way suggested I end up with:
Made progress! Can we adkjust it to still include the grid lines? Like in normal cells?
After
exchanging all ClipBounds by CellBounds
Deleting the g.Dispose();
..things look almost normal.
This is the result :
Of this Paint event:
private void dataGridView2_CellPainting(object sender,
DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex == 4 && e.RowIndex == 0) // use your own checks here!!
{
e.PaintBackground(e.CellBounds, true);
e.PaintContent(e.CellBounds);
Graphics g = e.Graphics;
Color c = Color.Empty;
string s = "";
Brush br = SystemBrushes.WindowText;
Brush brBack;
Rectangle rDraw;
rDraw = e.CellBounds;
rDraw.Inflate(-1, -1);
{
brBack = Brushes.White;
g.FillRectangle(brBack, rDraw); // **
}
try
{ // use your own code here again!
// ComboboxColorItem oColorItem =
// (ComboboxColorItem)((ComboBox)sender).SelectedItem;
s = "WW";// oColorItem.ToString();
c = Color.LawnGreen;// oColorItem.Value;
} catch
{
s = "red";
c = Color.Red;
}
// asuming a square is right; make it a few pixels smaller!
int butSize = e.CellBounds.Height;
Rectangle rbut = new Rectangle(e.CellBounds.Right - butSize ,
e.CellBounds.Top, butSize , butSize );
ComboBoxRenderer.DrawDropDownButton(e.Graphics, rbut,
System.Windows.Forms.VisualStyles.ComboBoxState.Normal);
SolidBrush b = new SolidBrush(c);
Rectangle r = new Rectangle( e.CellBounds.Left + 5,
e.CellBounds.Top + 3, 10, 10);
g.FillRectangle(b, r);
g.DrawRectangle(Pens.Black, r);
g.DrawString(s, Form.DefaultFont, Brushes.Black,
e.CellBounds.Left + 25, e.CellBounds.Top + 1);
b.Dispose();
//g.Dispose(); <-- do not dispose of thing you have not created!
e.Handled = true;
}
}
Note that I only have one CombBoxCell, so I changed the checks. And that I have no ComboboxColorItem, so I substituted a random string & color.
Update from OP: I had some of the syntax wrong and needed:
// use your own code here again!
if(DataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
{
ComboboxColorItem oColorItem = (ComboboxColorItem)DataGridView1
.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
s = oColorItem.ToString();
c = oColorItem.Value;
}
How to set combobox item height? My combobox.size=new size(320,40) and I had set combobox.itemheight=18 but it didn't work. I want my itemheight or text height to be 18, and fixed size for the combobox which is 320x40. I used also drawmode property but nothing is happening.
Try changing Font Size of your combo box
Well, in order to prevent combobox resizing to its default height, you can declare it being manually drawing:
myComboBox.DrawMode = DrawMode.OwnerDrawFixed; // or DrawMode.OwnerDrawVariable;
myComboBox.Height = 18; // <- what ever you want
Then you have to implement DrawItem event:
private void myComboBox_DrawItem(object sender, DrawItemEventArgs e) {
ComboBox box = sender as ComboBox;
if (Object.ReferenceEquals(null, box))
return;
e.DrawBackground();
if (e.Index >= 0) {
Graphics g = e.Graphics;
using (Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
? new SolidBrush(SystemColors.Highlight)
: new SolidBrush(e.BackColor)) {
using (Brush textBrush = new SolidBrush(e.ForeColor)) {
g.FillRectangle(brush, e.Bounds);
g.DrawString(box.Items[e.Index].ToString(),
e.Font,
textBrush,
e.Bounds,
StringFormat.GenericDefault);
}
}
}
e.DrawFocusRectangle();
}
Edit: to have the combobox stretched, but not its dropdown list
myComboBox.DrawMode = DrawMode.OwnerDrawVariable;
myComboBox.Height = 18; // Combobox itself is 18 pixels in height
...
private void myComboBox_MeasureItem(object sender, MeasureItemEventArgs e) {
e.ItemHeight = 17; // while item is 17 pixels high only
}
Straight to the question: Is it possible to insert a string in a subitem which each leter has a different color???
I would like to represent time delay using colors. Example:
Subitem string "10 14 50" and values 10 and 50 with color red and 14 with green.
Try setting the OwnerDraw mode to true and supply the drawing routine yourself:
listView1.OwnerDraw = true;
listView1.DrawColumnHeader += listView1_DrawColumnHeader;
listView1.DrawSubItem += listView1_DrawSubItem;
void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) {
e.DrawDefault = true;
}
void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) {
if (e.ColumnIndex == 1) {
e.Graphics.SetClip(e.Bounds);
using (SolidBrush br = new SolidBrush(listView1.BackColor)) {
e.Graphics.FillRectangle(br, e.Bounds);
}
int textLeft = e.Bounds.Left;
string[] subItems = e.Item.SubItems[1].Text.Split(' ');
for (int i = 0; i < subItems.Length; ++i) {
int textWidth = TextRenderer.MeasureText(subItems[i], listView1.Font).Width;
TextRenderer.DrawText(e.Graphics, subItems[i], listView1.Font,
new Rectangle(textLeft, e.Bounds.Top, textWidth, e.Bounds.Height),
i == 0 ? Color.Red : i == subItems.Length - 1 ? Color.Green : Color.Black,
Color.Empty,
TextFormatFlags.VerticalCenter | TextFormatFlags.PreserveGraphicsClipping);
textLeft += textWidth;
}
e.Graphics.ResetClip();
} else {
e.DrawDefault = true;
}
}
Result:
I am trying to draw items in a ComboBoxCell in a DataGridView using the DrawItem Event. Following is my code.
Updated Code:
private void dgv_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
int index = dgv.CurrentCell.ColumnIndex;
if (index == FormatColumnIndex)
{
var combobox = e.Control as ComboBox;
if (combobox == null)
return;
combobox.DrawMode = DrawMode.OwnerDrawFixed;
combobox.DrawItem -= combobox_DrawItem;
combobox.DrawItem += new DrawItemEventHandler(combobox_DrawItem);
}
}
void combobox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0)
{
return;
}
int index = dgv.CurrentCell.RowIndex;
if (index == e.Index)
{
DataGridViewComboBoxCell cmbcell = (DataGridViewComboBoxCell)dgv.CurrentRow.Cells["ProductFormat"];
string productID = dgv.Rows[cmbcell.RowIndex].Cells["ProductID"].Value.ToString();
string item = cmbcell.Items[e.Index].ToString();
if (item != null)
{
Font font = new System.Drawing.Font(FontFamily.GenericSansSerif, 8);
Brush backgroundColor;
Brush textColor;
if (e.State == DrawItemState.Selected)
{
backgroundColor = SystemBrushes.Highlight;
textColor = SystemBrushes.HighlightText;
}
else
{
backgroundColor = SystemBrushes.Window;
textColor = SystemBrushes.WindowText;
}
if (item == "Preferred" || item == "Other")
{
font = new Font(font, FontStyle.Bold);
backgroundColor = SystemBrushes.Window;
textColor = SystemBrushes.WindowText;
}
if (item != "Select" && item != "Preferred" && item != "Other")
e.Graphics.DrawString(item, font, textColor, new Rectangle(e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height));
else
e.Graphics.DrawString(item, font, textColor, e.Bounds);
}
}
}
}
The items are displayed properly, but the dropdown seems out of place and looks awkward.
Also when I hover over the dropdown items, they seem to be painted over again which makes them look darker and blurred. How can I fix this? Thanks.
Your drawing routine looks like it is confusing the RowIndex of the grid with the e.Index of the ComboBox items collection. Different things.
Try removing this:
// int index = dgv.CurrentCell.RowIndex;
// if (index == e.Index) {
As far as the blurriness is concerned, add the following line to fix that:
void combobox_DrawItem(object sender, DrawItemEventArgs e) {
e.DrawBackground();
I had the same problem and fixed it by setting the TextRenderingHint property of e.Graphics to SingleBitPerPixelGridFit before calling DrawString:
e.DrawBackground()
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit
e.Graphics.DrawString(lstr_h, e.Font, lbrush_fore, e.Bounds)
e.DrawFocusRectangle()
I am trying to work around changing the color of highlighting in a ComboBox dropdown on a C# Windows Forms application.
I have searched the whole web for an answer, and the best option i found so far was to draw a rectangle of the desired color when the item that is selected is being drawn.
Class Search
{
Public Search()
{
}
private void addFilter()
{
ComboBox field = new ComboBox();
field.Items.AddRange(new string[] { "Item1", "item2" });
field.Text = "Item1";
field.DropDownStyle = ComboBoxStyle.DropDownList;
field.FlatStyle = FlatStyle.Flat;
field.BackColor = Color.FromArgb(235, 235, 235);
field.DrawMode = DrawMode.OwnerDrawFixed;
field.DrawItem += field_DrawItem;
}
private void field_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index >= 0)
{
ComboBox combo = sender as ComboBox;
if (e.Index == combo.SelectedIndex)
e.Graphics.FillRectangle(new SolidBrush(Color.Gray),
e.Bounds
);
else
e.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
e.Bounds
);
e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font,
new SolidBrush(combo.ForeColor),
new Point(e.Bounds.X, e.Bounds.Y)
);
}
}
}
The problem with this code, is that once another Item in the dropdown is selected, the other Item I draw a rectangle is still with the color i want to highlight.
Then i tried to save the last Item drawn and redraw it:
Class Search
{
private DrawItemEventArgs lastDrawn;
Public Search()
{
lastDrawn = null;
}
private void addFilter()
{
ComboBox field = new ComboBox();
field.Items.AddRange(new string[] { "Item1", "item2" });
field.Text = "Item1";
field.DropDownStyle = ComboBoxStyle.DropDownList;
field.FlatStyle = FlatStyle.Flat;
field.BackColor = Color.FromArgb(235, 235, 235);
field.DrawMode = DrawMode.OwnerDrawFixed;
field.DrawItem += field_DrawItem;
}
private void field_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index >= 0)
{
ComboBox combo = sender as ComboBox;
if (e.Index == combo.SelectedIndex)
{
e.Graphics.FillRectangle(new SolidBrush(Color.Gray), e.Bounds);
if(lastDrawn != null)
lastDrawn.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
lastDrawn.Bounds
);
lastDrawn = e;
}
else
e.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
e.Bounds
);
e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font,
new SolidBrush(combo.ForeColor),
new Point(e.Bounds.X, e.Bounds.Y)
);
}
}
}
This line returns an error because of lastDrawn.Bounds (incompatible type)
lastDrawn.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
lastDrawn.Bounds
);
I am feeling that changing the highlight color of the dropdown is impossible.
Thanks in advance!
In case you are using the ComboBox in more than one place in your project, it will not make sense to repeat the same code for DrawItem event over and over again. Just add this class to your project and you will have a new ComboBox control that has the HightlightColor property which will makes it easier to use the control all over the project:
class AdvancedComboBox : ComboBox
{
new public System.Windows.Forms.DrawMode DrawMode { get; set; }
public Color HighlightColor { get; set; }
public AdvancedComboBox()
{
base.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
this.HighlightColor = Color.Gray;
this.DrawItem += new DrawItemEventHandler(AdvancedComboBox_DrawItem);
}
void AdvancedComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index < 0)
return;
ComboBox combo = sender as ComboBox;
if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
e.Graphics.FillRectangle(new SolidBrush(HighlightColor),
e.Bounds);
else
e.Graphics.FillRectangle(new SolidBrush(combo.BackColor),
e.Bounds);
e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font,
new SolidBrush(combo.ForeColor),
new Point(e.Bounds.X, e.Bounds.Y));
e.DrawFocusRectangle();
}
}