简体   繁体   中英

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

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.'

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;
                }
            }
        }
    }
}

Your question is How to color items in listBox in different colors? and the "Y" of what might be considered an XY Problem is that you get an exception when you try to Add an item inline. After carefully reading your code, something that would make a big difference would be using the MyListBoxItem type consistently in both in your DataSource and your Json serialization and deserialization, and then appending the data source when you wish to Add an item inline.

添加内联


Datasource

BindingList<MyListBoxItem> MyItems { get; } = new BindingList<MyListBoxItem>();

Example of MyItems in Json-Serialized form in the disk file

[
  {
    "ItemColor": "Blue",
    "Message": "Blue Item"
  },
  {
    "ItemColor": "Green",
    "Message": "Green Item"
  },
  {
    "ItemColor": "Red",
    "Message": "Red Item"
  }
]

Where:

public class MyListBoxItem
{ 
    public Color ItemColor { get; set; }
    public string Message { get; set; }
}

Main Form initialization for listBox1 drawing code

public partial class MainForm : Form
{
    public MainForm() => InitializeComponent();
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        listBox1.DisplayMember = nameof(MyListBoxItem.Message);
        listBox1.DataSource = MyItems;
        listBox1.DrawItem += onDrawItem;
        listBox1.DrawMode = DrawMode.OwnerDrawFixed;
        listBox1.SelectedIndexChanged += (sender, e) => listBox1.Refresh();

        // Tests
        buttonTest.Click += onButtonTest;
        buttonReadJson.Click += onButtonReadJson;
    }
    private void onDrawItem(object sender, DrawItemEventArgs e)
    {
        if((e.Index == -1) || (e.Index >= MyItems.Count))
        {                
            e.DrawBackground();
        }
        else
        {
            var myItem = MyItems[e.Index];
            if (listBox1.SelectedItems.Contains(myItem))
            {
                using (var backgroundBrush = new SolidBrush(myItem.ItemColor))
                {
                    e.Graphics.FillRectangle(backgroundBrush, e.Bounds);
                }

                using (var textBrush = new SolidBrush(Color.White))
                {
                    e.Graphics.DrawString(myItem.Message, listBox1.Font, textBrush, e.Bounds);
                }
            }
            else
            {
                using (var backgroundBrush = new SolidBrush(SystemColors.Window))
                {
                    e.Graphics.FillRectangle(backgroundBrush, e.Bounds);
                }
                using (var textBrush = new SolidBrush(myItem.ItemColor))
                {
                    e.Graphics.DrawString(myItem.Message, listBox1.Font, textBrush, e.Bounds);
                }
            }
        }
    }
    BindingList<MyListBoxItem> MyItems { get; } = new BindingList<MyListBoxItem>();
    .
    .
    .
}

Example of adding items

private void onButtonTest(object sender, EventArgs e)
{
    MyItems.Clear();
    MyItems.Add(new MyListBoxItem
    {
        Message = "Validated data successfully",
        ItemColor = Color.Green,
    });
    MyItems.Add(new MyListBoxItem
    {
        Message = "Failed to validate data",
        ItemColor = Color.Red,
    });
}

Example of deserializing file

json反序列化

private void onButtonReadJson(object sender, EventArgs e)
{
    MyItems.Clear();
    foreach (
        var myItem 
        in JsonConvert.DeserializeObject<List<MyListBoxItem>>(mockFileContents))
    {
        MyItems.Add(myItem);
    }
}

const string mockFileContents = 
@"[
  {
    ""ItemColor"": ""Blue"",
    ""Message"": ""Blue Item""
  },
  {
    ""ItemColor"": ""Green"",
    ""Message"": ""Green Item""
  },
  {
    ""ItemColor"": ""Red"",
    ""Message"": ""Red Item""
  }
]";

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM