Имеется комбо-бокс, связанный с источником данных. Задача: раскрасить строки в разные цвета по какому-то критерию, связанному с источником данных.
Чтобы решить эту задачу придется изменить отрисовку на экране строк комбо-бокса повесившись на событие DrawItem. По умолчанию это событие не происходит, чтобы оно начало работать надо поставить свойство ComboBox DrawMode в значение OwnerDrawVariable или OwnerDrawFixed из перечисления DrawMode
Если наш комбо-бокс заполнен простым массивом или списком строк и не привязан к сложному источнику данных с DisplayMember и ValueMember, то код раскраски внутри события (в зависимости от строки) будет примерно таким
// заполнение коллекции элементов for (int counter = 1; counter <= 10; counter++) { _testNonBindedComboBox.Items.Add(counter.ToString()); } _testNonBindedComboBox.SelectedIndex = 3; _testNonBindedComboBox.DrawMode = DrawMode.OwnerDrawVariable;
//private void _testComboBox_DrawItem(object sender, DrawItemEventArgs e) e.DrawBackground(); // в событие комбобокс передается в универсальнмо типе Object, конвертируем в комбо-бокс ComboBox currComboBox = (ComboBox)sender; currComboBox.SelectedIndex = e.Index; string text = currComboBox.Items[e.Index].ToString(); int textInteger = Convert.ToInt32(text); // определяем цвет для текущей строки Brush brush; if (textInteger < 3) { brush = Brushes.Red; } else if (textInteger > 3 && textInteger < 6) { brush = Brushes.Green; } else { brush = Brushes.Blue; } // прорисовываем текст в строке комбо-бокса e.Graphics.DrawString(text, currComboBox.Font, brush, e.Bounds.X, e.Bounds.Y);
Но в реальной жизни комбо-бокс чаще всего привязан к DataTable, каждая строка имеет и видимое значение и код, раскраска же может зависеть от каких-нибудь дополнительных полей, который надежнее всего получать по коду (так как на таблицу могут динамически накладываться фильтры). Здесь возникает проблема - во время отрисовки мы обходим все элементы, но напрямую получить ValueItem по интексу элемента в items невозможно, каждый item имеет тип object и возвращает DisplayValue через ToString(). В данном случае внутрии коллекции items будут на самом деле сидеть обьекти класса DataRowView, через которые можно уже достучаться до исходного DataRow.
Если таблица-источник имеет три колонки ID, TYPE и TEXT, то получить значение TYPE по ID и в зависимости от него раскрасить строки можно следующим образом
//private void _testComboBox_DrawItem(object sender, DrawItemEventArgs e) e.DrawBackground(); // в событие комбобокс передается в универсальнмо типе Object, конвертируем в комбо-бокс ComboBox currComboBox = (ComboBox)sender; // вернет System.DataRow.DataRowView так как на самом деле там сидит обьект класса DataRowView //string text = currComboBox.Items[e.Index].ToString(); DataRowView currIntemDRView = (DataRowView)currComboBox.Items[e.Index]; string text = currIntemDRView.Row["TEXT"].ToString(); int id = Convert.ToInt32(currIntemDRView.Row["ID"]); // в реальном проекте может быть сложнее, иллюстрируем общую идею зависимости цвета от кода строки int type = 0; foreach (DataRow currRow in _testTable.Rows) { int currId = (int)currRow["ID"]; if (currId == id) { type = (int)currRow["TYPE"]; break; } } // определяем цвет для текущей строки Brush brush; if (type == 0) { brush = Brushes.Red; } else if (type == 1) { brush = Brushes.Green; } else { brush = Brushes.Blue; } // прорисовываем текст в строке комбо-бокса e.Graphics.DrawString(text, currComboBox.Font, brush, e.Bounds.X, e.Bounds.Y);
Есть один интересный момент, низкоуровневое событие DrawItem происходит очень часто, намного чаще привычных логических событий вроде cмены выбранного элемента. Чтобы наглядно продемонстрировать эту частоту в тестовом проекте добавлена метка, по которой наглядно видно, что за пару секунд работы с открытием-закрытием списка событие срабатывает сотни раз. Таким образом медленные операции и операции меняющие состояние самого ComboBox (что может вызвать рекурсивный вызов этого события заново) надо вешать на него с большой осторожностью. Коллега получила переполнение буфера в mscorlib.dll по совершенно невнятным причинам.
Тестовый проект с демонстрацией вышеописанного
Тестовый проект ColorComboBox в .zip
Дополнительно: