How to color items in listBox in different colors? getting exception : Items collection cannot be modified when the DataSource property is set

Chocolade 536 Reputation points
2023-01-01T17:01:37.87+00:00

In the designer in the listBox1 properties i set the DrawMode to OwnerDrawFixed

Then added this class for the coloring :

public class MyListBoxItem  
        {  
            public MyListBoxItem(Color c, string m)  
            {  
                ItemColor = c;  
                Message = m;  
            }  
            public Color ItemColor { get; set; }  
            public string Message { get; set; }  
        }  

and added event of the DrawItem :

private void listBox1_DrawItem(object sender, DrawItemEventArgs e)  
        {  
            MyListBoxItem item = listBox1.Items[e.Index] as MyListBoxItem; // Get the current item and cast it to MyListBoxItem  
            if (item != null)  
            {  
                e.Graphics.DrawString( // Draw the appropriate text in the ListBox  
                    item.Message, // The message linked to the item  
                    listBox1.Font, // Take the font from the listbox  
                    new SolidBrush(item.ItemColor), // Set the color   
                    0, // X pixel coordinate  
                    e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.  
                );  
            }  
            else  
            {  
                // The item isn't a MyListBoxItem, do something about it  
            }  
        }  

then i'm trying to add some items just for testing in the constructor : each item should be in another color :

listBox1.Items.Add(new MyListBoxItem(Colors.Green, "Validated data successfully"));  
listBox1.Items.Add(new MyListBoxItem(Colors.Red, "Failed to validate data"));  

but getting exception on the first listBox1.Items.Add line :

System.ArgumentException: 'Items collection cannot be modified when the DataSource property is set.'

i understand i can use either Items.Add or DataSource and can't mix them
and i also tested by removing the DataSource part in the constructor then used the Items.Add and it's coloring the items fine.

but how can i color each item in another color with the DataSource ?

and this is the full code :

using Newtonsoft.Json;  
using Ookii.Dialogs.WinForms;  
using System;  
using System.Collections.Generic;  
using System.ComponentModel;  
using System.Data;  
using System.Drawing;  
using System.Drawing.Drawing2D;  
using System.Drawing.Imaging;  
using System.IO;  
using System.Linq;  
using System.Security.Cryptography;  
using System.Text;  
using System.Threading.Tasks;  
using System.Windows.Forms;  
using static System.Windows.Forms.VisualStyles.VisualStyleElement;  
using static System.Windows.Forms.VisualStyles.VisualStyleElement.ProgressBar;  
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Window;  
  
namespace Image_Crop  
{  
    public partial class Form1 : Form  
    {  
        Rectangle rect;  
        int pixelsCounter = 0;  
        Color SelectedColor = Color.LightGreen;  
        List<DrawingRectangle> DrawingRects = new List<DrawingRectangle>();  
        Bitmap rectImage;  
        int saveRectanglesCounter = 1;  
        bool drawBorder = true;  
        bool clearRectangles = true;  
        bool saveRectangles = true;  
        string rectangleName;  
        Dictionary<string, string> FileList = new Dictionary<string, string>();  
        string selectedPath;  
        int x, y;  
        private bool crop = false;  
  
        public Form1()  
        {  
            InitializeComponent();  
  
            textBox1.Text = Properties.Settings.Default.ImageToCropFolder;  
            textBox2.Text = Properties.Settings.Default.CroppedImagesFolder;  
  
            selectedPath = textBox2.Text;  
  
            if (textBox1.Text != "")  
            {  
                Bitmap bmp = new Bitmap(Image.FromFile(textBox1.Text),  
                    pictureBox2.Width, pictureBox2.Height);  
                pictureBox2.Image = bmp;  
            }  
              
            checkBoxDrawBorder.Checked = true;  
            checkBoxClearRectangles.Checked = true;  
            checkBoxSaveRectangles.Checked = true;  
  
            if (selectedPath != "" && selectedPath != null)  
            {  
                if (System.IO.File.Exists(Path.Combine(selectedPath, "rectangles.txt")))  
                {  
                    string g = System.IO.File.ReadAllText(Path.Combine(selectedPath, "rectangles.txt"));  
                    g = g.Remove(0, 32);  
                      
                    FileList = JsonConvert.DeserializeObject<Dictionary<string, string>>(g);  
                    listBox1.DataSource = FileList.Keys.ToList();  
                    label2.Text = listBox1.Items.Count.ToString();  
                    listBox1.SelectedIndex = listBox1.Items.Count - 1;  
                }  
                else  
                {  
                    label2.Text = "0";  
                }  
            }  
            else  
            {  
                label2.Text = "0";  
            }  
  
            if ((selectedPath != "" && selectedPath != null) && textBox1.Text != "")  
            {  
                crop = true;  
            }  
            else  
            {  
                crop = false;  
            }  
  
            listBox1.Items.Add(new MyListBoxItem(Color.Green, "Validated data successfully"));  
            listBox1.Items.Add(new MyListBoxItem(Color.Red, "Failed to validate data"));  
        }  
  
        public class DrawingRectangle  
        {  
            public Rectangle Rect => new Rectangle(Location, Size);  
            public Size Size { get; set; }  
            public Point Location { get; set; }  
            public Control Owner { get; set; }  
            public Point StartPosition { get; set; }  
            public Color DrawingcColor { get; set; } = Color.LightGreen;  
            public float PenSize { get; set; } = 3f;  
        }  
  
        private void Form1_Load(object sender, EventArgs e)  
        {  
  
        }  
  
        private void pictureBox2_MouseDown(object sender, MouseEventArgs e)  
        {  
            if (e.Button != MouseButtons.Left || crop == false) return;  
  
            x = 0;  
            y = 0;  
  
            if (pictureBox2.Image != null && selectedPath != null)  
            {  
                if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))  
                {  
                    DrawingRects.Add(new DrawingRectangle()  
                    {  
                        Location = e.Location,  
                        Size = Size.Empty,  
                        StartPosition = e.Location,  
                        Owner = (Control)sender,  
                        DrawingcColor = SelectedColor  
                    });  
                }  
            }  
        }  
  
        private void pictureBox2_MouseMove(object sender, MouseEventArgs e)  
        {  
            int X = e.X;  
            int Y = e.Y;  
  
            if (e.Button != MouseButtons.Left || crop == false) return;  
  
  
            if ((X >= 0 && X <= pictureBox2.Width) && (Y >= 0 && Y <= pictureBox2.Height))  
            {  
                if (pictureBox2.Image != null && selectedPath != null && DrawingRects.Count > 0)  
                {  
                    if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))  
                    {  
                        x = e.X;  
                        y = e.Y;  
  
                        var dr = DrawingRects[DrawingRects.Count - 1];  
                        if (e.Y < dr.StartPosition.Y) { dr.Location = new Point(dr.Rect.Location.X, e.Y); }  
                        if (e.X < dr.StartPosition.X) { dr.Location = new Point(e.X, dr.Rect.Location.Y); }  
  
                        dr.Size = new Size(Math.Abs(dr.StartPosition.X - e.X), Math.Abs(dr.StartPosition.Y - e.Y));  
                        pictureBox2.Invalidate();  
                    }  
                }  
            }  
  
        }  
  
        int count = 0;  
        private void pictureBox2_MouseUp(object sender, MouseEventArgs e)  
        {  
            if (e.Button != MouseButtons.Left || crop == false) return;  
  
            if (DrawingRects.Count > 0 && pictureBox2.Image != null && selectedPath != "")  
            {  
                if ((x >= 0 && x <= pictureBox2.Image.Size.Width) && (y >= 0 && y <= pictureBox2.Image.Size.Height))  
                {  
                    var dr = DrawingRects.Last();  
                    if (dr.Rect.Width > 0 && dr.Rect.Height > 0)  
                    {  
                        rectImage = cropAtRect((Bitmap)pictureBox2.Image, dr.Rect);  
  
                        if (saveRectangles)  
                        {  
                            count++;  
                            rectangleName = GetNextName(Path.Combine(selectedPath, "Rectangle"), ".bmp");  
                            FileList.Add($"{dr.Location}, {dr.Size}", rectangleName);  
                            string json = JsonConvert.SerializeObject(  
        FileList,  
        Formatting.Indented  
    );  
                            using (StreamWriter sw = new StreamWriter(Path.Combine(selectedPath, "rectangles.txt"), false))  
                            {  
                                sw.WriteLine("Total number of rectangles: " + count + Environment.NewLine);  
                                sw.Write(json);  
                                sw.Close();  
                            }  
  
                            rectImage.Save(rectangleName);  
                            saveRectanglesCounter++;  
                        }  
                        else  
                        {  
                            var stream = ToMemoryStream(rectImage);  
                            var image  = System.Drawing.Image.FromStream(stream);  
                            pictureBox1.Image = image;  
                        }  
                          
                        pixelsCounter = rect.Width * rect.Height;  
                        pictureBox1.Invalidate();  
                        listBox1.DataSource = FileList.Keys.ToList();  
                        listBox1.SelectedIndex = listBox1.Items.Count - 1;  
  
                        pictureBox2.Focus();  
                        Graphics g = Graphics.FromImage(this.pictureBox1.Image);  
                        g.Clear(this.pictureBox1.BackColor);  
                    }  
                }  
                else  
                {  
                    if (clearRectangles)  
                    {  
                        DrawingRects.Clear();  
                        pictureBox2.Invalidate();  
                    }  
  
                    x = 0;  
                    y = 0;  
                }  
            }  
        }  
  
        public class MyListBoxItem  
        {  
            public MyListBoxItem(Color c, string m)  
            {  
                ItemColor = c;  
                Message = m;  
            }  
            public Color ItemColor { get; set; }  
            public string Message { get; set; }  
        }  
  
        public MemoryStream ToMemoryStream(Bitmap b)  
        {  
            MemoryStream ms = new MemoryStream();  
            b.Save(ms, System.Drawing.Imaging.ImageFormat.Png);  
            return ms;  
        }  
  
        string GetNextName(string baseName, string extension)  
        {  
            int counter = 1;  
            string nextName = baseName + counter + extension;  
            while (System.IO.File.Exists(nextName))  
            {  
                counter++;  
                nextName = baseName + counter + extension;  
            }  
            return nextName;  
        }  
  
        private void pictureBox2_Paint(object sender, PaintEventArgs e)  
        {  
            if (drawBorder)  
            {  
                ControlPaint.DrawBorder(e.Graphics, pictureBox2.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);  
            }  
  
            if (pictureBox2.Image != null && selectedPath != null && DrawingRects.Count > 0)  
            {  
                DrawShapes(e.Graphics);  
            }  
        }  
  
        private void pictureBox1_Paint(object sender, PaintEventArgs e)  
        {  
            if (drawBorder)  
            {  
                ControlPaint.DrawBorder(e.Graphics, pictureBox1.ClientRectangle, Color.Red, ButtonBorderStyle.Solid);  
            }  
  
            if (rectImage != null && DrawingRects.Count > 0)  
            {  
                var dr = DrawingRects.Last();  
                e.Graphics.DrawImage(rectImage, dr.Rect);  
  
                if (clearRectangles)  
                {  
                    DrawingRects.Clear();  
                    pictureBox2.Invalidate();  
                }  
            }  
        }  
  
        private void DrawShapes(Graphics g)  
        {  
            if (DrawingRects.Count == 0) return;  
            g.SmoothingMode = SmoothingMode.AntiAlias;  
            foreach (var dr in DrawingRects)  
            {  
                if (dr.Rect.Width > 0 && dr.Rect.Height > 0)  
                {  
                    using (Pen pen = new Pen(dr.DrawingcColor, dr.PenSize))  
                    {  
                        g.DrawRectangle(pen, dr.Rect);  
                    };  
                }  
            }  
        }  
  
        public Bitmap cropAtRect(Bitmap b, Rectangle r)  
        {  
            Bitmap nb = new Bitmap(r.Width, r.Height);  
            using (Graphics g = Graphics.FromImage(nb))  
            {  
                g.DrawImage(b, -r.X, -r.Y);  
                return nb;  
            }  
        }  
  
        private void checkBoxDrawBorder_CheckedChanged(object sender, EventArgs e)  
        {  
            if (checkBoxDrawBorder.Checked)  
            {  
                drawBorder = true;  
            }  
            else  
            {  
                drawBorder = false;  
            }  
  
            pictureBox1.Invalidate();  
            pictureBox2.Invalidate();  
        }  
  
        private void checkBoxClearRectangles_CheckedChanged(object sender, EventArgs e)  
        {  
            if (checkBoxClearRectangles.Checked)  
            {  
                clearRectangles = true;  
            }  
            else  
            {  
                clearRectangles = false;  
            }  
  
            pictureBox2.Invalidate();  
        }  
  
        private void checkBoxSaveRectangles_CheckedChanged(object sender, EventArgs e)  
        {  
            if(checkBoxSaveRectangles.Checked)  
            {  
                saveRectangles = true;  
            }  
            else  
            {  
                saveRectangles = false;  
            }  
        }  
  
        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)  
        {  
            var item = ((ListBox)sender).SelectedItem;  
            var val = FileList[(string)item];  
            if (File.Exists(val))  
            {  
                pictureBox1.Image = System.Drawing.Image.FromFile(val);  
            }  
        }  
  
        private void button1_Click(object sender, EventArgs e)  
        {  
            VistaOpenFileDialog dialog = new VistaOpenFileDialog();  
            {  
                dialog.Filter = "Images (*.jpg, *.bmp, *.gif)|*.jpg;*.bmp;*.gif";  
            };  
  
            if (dialog.ShowDialog() == DialogResult.OK)  
            {  
                textBox1.Text = dialog.FileName;  
  
                Properties.Settings.Default.ImageToCropFolder = dialog.FileName;  
                Properties.Settings.Default.Save();  
  
                Bitmap bmp = new Bitmap(Image.FromFile(dialog.FileName),  
                    pictureBox2.Width, pictureBox2.Height);  
                pictureBox2.Image = bmp;  
  
                if(textBox1.Text != "" && textBox2.Text != "")  
                {  
                    crop = true;  
                }  
            }  
        }  
  
        private void listBox1_DrawItem(object sender, DrawItemEventArgs e)  
        {  
            MyListBoxItem item = listBox1.Items[e.Index] as MyListBoxItem; // Get the current item and cast it to MyListBoxItem  
            if (item != null)  
            {  
                e.Graphics.DrawString( // Draw the appropriate text in the ListBox  
                    item.Message, // The message linked to the item  
                    listBox1.Font, // Take the font from the listbox  
                    new SolidBrush(item.ItemColor), // Set the color   
                    0, // X pixel coordinate  
                    e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.  
                );  
            }  
            else  
            {  
                // The item isn't a MyListBoxItem, do something about it  
            }  
        }  
  
        private void button2_Click(object sender, EventArgs e)  
        {  
            VistaFolderBrowserDialog dialog = new VistaFolderBrowserDialog();  
  
            if (dialog.ShowDialog() == DialogResult.OK)  
            {  
                textBox2.Text = dialog.SelectedPath;  
                selectedPath = dialog.SelectedPath;  
  
                Properties.Settings.Default.CroppedImagesFolder = selectedPath;  
                Properties.Settings.Default.Save();  
  
                if (textBox1.Text != "" && textBox2.Text != "")  
                {  
                    crop = true;  
                }  
            }  
        }  
    }  
}  
Developer technologies Windows Forms
Developer technologies C#
0 comments No comments
{count} votes

Accepted answer
  1. Jack J Jun 25,296 Reputation points
    2023-01-02T09:24:58.463+00:00

    @Chocolade , Welcome to Microsoft Q&A, based on my test, I reproduced your problem. Also, the error means that you could not add an item to a binding control. I suggest that you could use the loop to add the data for FileList.

    Meanwhile, we need to write some code for the item is not the MyListBoxItem.

    Here is a code example you could refer to.

    if (System.IO.File.Exists(Path.Combine(selectedPath, "rectangles.txt")))  
                     {  
                         string g = System.IO.File.ReadAllText(Path.Combine(selectedPath, "rectangles.txt"));  
                         g = g.Remove(0, 32);  
                              
                         FileList = JsonConvert.DeserializeObject<Dictionary<string, string>>(g);  
                         foreach (var item in FileList)  
                          {  
                          listBox1.Items.Add(item);  
                          }  
                         label2.Text = listBox1.Items.Count.ToString();  
                         listBox1.SelectedIndex = listBox1.Items.Count - 1;  
                     }  
    

    Then, we need to write some code in listbox_Drawitem event.

      private void listBox1_DrawItem(object sender, DrawItemEventArgs e)  
            {  
                MyListBoxItem item = listBox1.Items[e.Index] as MyListBoxItem; // Get the current item and cast it to MyListBoxItem  
                if (item != null)  
                {  
                    e.Graphics.DrawString( // Draw the appropriate text in the ListBox  
                        item.Message, // The message linked to the item  
                        listBox1.Font, // Take the font from the listbox  
                        new SolidBrush(item.ItemColor), // Set the color   
                        0, // X pixel coordinate  
                        e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.  
                    );  
                }  
                else  
                {  
                    string newitem = listBox1.Items[e.Index].ToString();  
                    e.Graphics.DrawString( // Draw the appropriate text in the ListBox  
                       newitem, // The message linked to the item  
                       listBox1.Font, // Take the font from the listbox  
                       new SolidBrush(Color.Black), // Set the color   
                       0, // X pixel coordinate  
                       e.Index * listBox1.ItemHeight // Y pixel coordinate.  Multiply the index by the ItemHeight defined in the listbox.  
                   );  
                    // The item isn't a MyListBoxItem, do something about it  
                }  
            }  
    

    Tested result:

    275318-image.png

    Best Regards,
    Jack


    If the answer is the right solution, please click "Accept Answer" and upvote it.If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.