I fill a listbox listBoxHome from a dictionary dictionaryHome :
dictionaryHome.Add(item.Id, item.Name);
listBoxHome.DataSource = new BindingSource(dictionaryHome, null);
listBoxHome.DisplayMember = "Value";
listBoxHome.ValueMember = "Key";
I also use the following code to be able only first 5 items to be selectable
private void listBoxHome_SelectedIndexChanged(object sender, EventArgs e)
{
InvertMySelection(listBoxHome, listBoxAway);
//make only first5 selectable
for (int i = 5; i < listBoxHome.Items.Count; i++)
{
if (listBoxHome.GetSelected(i) == true)
listBoxHome.ClearSelected();
}
}
I want to apply a different color to the first 5 items and different color the other items.
Or maybe a transparent panel that shows difference from the first 5 items and the other items. Also I want to draw a line inside the listbox as shown in the image. Any suggestion?
EDIT:
Adding Luc Morin's code the result shown in the following picture
Is there a way to show only the text and not the id(as was before)?The id is used in the back.
First you need to set the DrawMode to OwnerDrawFixed in the Windows Forms Designer property grid.
Then, add an event handler to the ListBox.DrawItem event, something along those lines:
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
// Draw the background of the ListBox control for each item.
e.DrawBackground();
// Define the default color of the brush as black.
Brush myBrush = Brushes.Black;
// Determine the color of the brush to draw each item based
// on the index of the item to draw.
if (e.Index < 3)
{
myBrush = Brushes.Red;
}
// Draw the current item text based on the current Font
// and the custom brush settings.
e.Graphics.DrawString(((KeyValuePair<int, string>)listBox1.Items[e.Index]).Value,
e.Font, myBrush, e.Bounds, StringFormat.GenericDefault);
// If the ListBox has focus, draw a focus rectangle around the selected item.
e.DrawFocusRectangle();
}
Adapt to your specific needs.
Code adapted from MSDN sample at: http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.drawitem(v=vs.110).aspx
Cheers
EDIT: In order to prevent selection of items, handle the ListBox.SelectedIhanged, something like this:
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if(listBox1.SelectedIndex >=3)
{
listBox1.SelectedIndex = -1;
listBox1.Invalidate();
}
}
EDIT 2: When binding to a dictionary, the ListBox.Items collection actually contains KeyValuePair objects instead of just strings. I updated the code to account for this. My example assumes the Key is an int and the Value is a string.
Related
I am trying to get the selected ListViewItem index, so that when the user clicks on a particular row, such as row 2, I want the clicked cell's text to be set to a TextBox's text.
I also want to highlight only this cell, ideally using the regular selection ListView uses, or do I need to create a class that inherits from ListView to do this?
Something like this:
You can draw yourself the ListViewItem.ListViewSubItem selected, owner-drawing the Control (set ListView.OwnerDraw = true), then handle the ListView.DrawSubItem event.
The ListView.DrawColumnHeader event can use default values.
▶ I'm using TextRenderer since this is the default renderer. If you use Graphics.DrawText, you'll notice the difference.
TextFormatFlags flags = TextFormatFlags.LeftAndRightPadding |
TextFormatFlags.VerticalCenter;
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
var lv = sender as ListView;
var subItem = lv.HitTest(lv.PointToClient(MousePosition)).SubItem;
if (subItem != null && e.SubItem == subItem) {
using (var brush = new SolidBrush(SystemColors.Highlight)) {
e.Graphics.FillRectangle(brush, e.SubItem.Bounds);
}
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, e.SubItem.Font,
e.Bounds, SystemColors.HighlightText, flags);
}
else {
e.DrawDefault = true;
}
}
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
=> e.DrawDefault = true;
// Invalidate on a mouse interaction, otherwise the ListView doesn't redraw the SubItem
private void listView1_MouseUp(object sender, MouseEventArgs e)
=> (sender as ListView).Invalidate();
Or, you can change the Colors of a SubItem when a mouse interaction is notified (here, using the MouseDown event) and save the previous state (just the Colors here). It's better to save the state because each SubItem can have it's own settings, so you cannot just revert back to the Parent ListViewItem or the ListView values.
As mentioned, set UseItemStyleForSubItems = false in each parent ListViewItem, otherwise the Colors settings are ignored.
Also, FullRowSelect must be set to false, otherwise it's pointless :)
Here, the state is saved in a nullable named Tuple Field, (ListViewSubItem, Color[]).
A class object is probably better, this is just shorter.
private (ListViewItem.ListViewSubItem Item, Color[] colors)? previousItem = null;
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
var lv = sender as ListView;
var subItem = lv.HitTest(e.Location).SubItem;
if (previousItem.HasValue) {
// If an Item's Colors have been changed, restore the state
// It removes the selection if you click in an empty area
previousItem.Value.Item.BackColor = previousItem.Value.colors[0];
previousItem.Value.Item.ForeColor = previousItem.Value.colors[1];
lv.Invalidate(previousItem.Value.Item.Bounds);
}
if (subItem != null) {
// Save the SubItem's colors state
previousItem = (subItem, new[] { subItem.BackColor, subItem.ForeColor });
// Set new Colors. Here, using the default highlight colors
subItem.BackColor = SystemColors.Highlight;
subItem.ForeColor = SystemColors.HighlightText;
lv.Invalidate(subItem.Bounds);
}
}
This is how this thing works:
▶ About the Item / SubItem index, as it's mentioned in the question:
When you retrieve the ListViewItem / SubItem clicked with ListView.HitTest
var hitTest = lv.HitTest(e.Location);
then the ListViewItem index is of course:
var itemIndex = hitTest.Item.Index;
and the SubItem.Index is:
var subItemIndex = hitTest.Item.SubItems.IndexOf(hitTest.SubItem);
Is there a toolbox object that is like a listbox but each individual item can have a different font colour? I'm trying to make a mod manager of sorts and want to grey out the text for those mods that are uninstalled.
Try this:
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
e.Graphics.DrawString(Convert.ToString(listBox1.Items[e.Index]), new Font("Aerial", 8), Brushes.Gray, new Point(0, 0));
e.DrawFocusRectangle();
}
For this to work, change the DrawMode of the Listbox to OwnerDrawFixed.
Also, if you want to select an item in a combobox, try something like this:
comboBox1.SelectedIndex = 0;
Hi guys I am trying to rebrush individual items in a listbox, I went with listbox draw item event, somehow it works but when I add items to my listbox, only string "b" is added and never the + "hi" part, I could write whatever I want or add whatever I want, only string b will be printed.
Not using draw mode and sticking with normal listbox obviously fixes the issue, so I guess it must be related to draw item event, but I cant figue out what exactly does this, I appreciate any help
listBox3.DrawMode = DrawMode.OwnerDrawFixed;
private async void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
foreach (string b in liIDs)
{
listBox3.Invoke((MethodInvoker)delegate
{
listBox3.Items.Add(b + "hi");
listBox3.Update();
});
}
private void listBox3_DrawItem(object sender, DrawItemEventArgs e)
{
try
{
e.DrawBackground();
Brush myBrush = Brushes.White;
myBrush = Brushes.Red;
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
e.Font, myBrush, e.Bounds, StringFormat.GenericDefault);
e.DrawFocusRectangle();
}
catch
{
}
}
I could only reproduce using items with values width larger than the list box width.
If thats the case you need to set the HorizontalScrollbar propertie to True and HorizontalExtent value
I'm currently working on some software and the customer is dead-set on a specific UI change that has been giving me some trouble:
I would like items in a ListView to not have any indentation. To illustrate I changed the backcolor of the ListView and the items.
Now, the little piece to the left of each item should also be white. Any ideas?
You can set the OwnerDraw property of ListView to true and using DrawItem, DrawColumnHeader and DrawSubItem draw the list view yourself.
For example:
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e)
{
e.Graphics.DrawString(e.Item.Text, e.Item.Font, Brushes.Black,
new Rectangle(e.Bounds.Left-2, e.Bounds.Top, e.Bounds.Width, e.Bounds.Height));
}
private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.DrawDefault = true;
}
private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
if(e.ColumnIndex>0)
e.DrawDefault = true;
}
Note:
The above rendering is just an example and shows you how you can draw item text in desired location for example using using Graphics.DrawString.
Also it shows you how to set e.DrawDefault = true; to perform default rendering.
The first subitem of each ListViewItem object represents the parent item itself
To avoid issues with graphics flickering when owner drawing, override the ListView control and set the DoubleBuffered property to true.
To learn more, read documents of OwnerDraw property of ListView control.
I'm trying to insert items in a listbox, but I want to color the text of specific items, depending on an integer. How can I insert an item with a specific color in the listbox ?
Thanks!
Set the DrawMode to OwnerDrawFixed of your Listbox control. and associate listBox_DrawItem event handler to it listbox draw item
private void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
e.DrawBackground();
Graphics yourObj = e.Graphics;
yourObj .FillRectangle(new SolidBrush(Color.Red), e.Bounds);
e.DrawFocusRectangle();
}
Description
A ListBox Item can be a object of any type. That means you cant set the color for a ListBox item at the moment you add them.
You need the DrawItem event.
ListBox.DrawItem Event Occurs when a visual aspect of an owner-drawn ListBox changes.
Sample
private void lstBox_DrawItem(object sender, _
System.Windows.Forms.DrawItemEventArgs e)
{
//
// Draw the background of the ListBox control for each item.
// Create a new Brush and initialize to a Black colored brush
// by default.
//
e.DrawBackground();
Brush myBrush = Brushes.Black;
//
// Determine the color of the brush to draw each item based on
// the index of the item to draw.
//
switch (e.Index)
{
case 0:
myBrush = Brushes.Red;
break;
case 1:
myBrush = Brushes.Orange;
break;
case 2:
myBrush = Brushes.Purple;
break;
}
//
// Draw the current item text based on the current
// Font and the custom brush settings.
//
e.Graphics.DrawString(((ListBox)sender).Items[e.Index].ToString(),
e.Font, myBrush,e.Bounds,StringFormat.GenericDefault);
//
// If the ListBox has focus, draw a focus rectangle
// around the selected item.
//
e.DrawFocusRectangle();
}
More Information
Change the Color of Individual .Net ListBox items
ListBox.DrawItem Event
Maybe this code will give you some idea...
listView1.Items.Clear();
int k = 0;
foreach (Player p in players)
{
ListViewItem lvitem = new ListViewItem();
lvitem.Text = p.name;
lvitem.BackColor = p.color;
listView1.Items.Add(lvitem);
k++;
}
Player is the class. It has name and color.