Отключение отдельных элементов в Combobox
У меня есть приложение WinForms, и мне было интересно, был ли более элегантный способ отключения элемента Combobox без изменения свойства SelectedIndex -1 для всех отключенных значений.
Я работаю в Google, и многие решения включают ASP.Net DropDownLists, но этот LINK выглядит многообещающим. Я думаю, мне, возможно, придется создать собственный контроллер ComboBox, но прежде чем я заново изобрету колесо, я думаю, что попрошу здесь, если бы это было возможно.
UPDATE
Вот окончательное решение, благодаря Arif Eqbal:
//Add a Combobox to a form and name it comboBox1
//
using System;
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
this.comboBox1.DrawItem += new System.Windows.Forms.DrawItemEventHandler(this.comboBox1_DrawItem);
this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged);
}
private void Form1_Load(object sender, EventArgs e)
{
this.comboBox1.Items.Add("Test1");
this.comboBox1.Items.Add("Test2");
this.comboBox1.Items.Add("Test3");
this.comboBox1.Items.Add("Test4");
this.comboBox1.Items.Add("Test5");
this.comboBox1.Items.Add("Test6");
this.comboBox1.Items.Add("Test7");
}
Font myFont = new Font("Aerial", 10, FontStyle.Underline|FontStyle.Regular);
Font myFont2 = new Font("Aerial", 10, FontStyle.Italic|FontStyle.Strikeout);
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == 1 || e.Index == 4 || e.Index == 5)//We are disabling item based on Index, you can have your logic here
{
e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), myFont2, Brushes.LightSlateGray, e.Bounds);
}
else
{
e.DrawBackground();
e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), myFont, Brushes.Black, e.Bounds);
e.DrawFocusRectangle();
}
}
void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 1 || comboBox1.SelectedIndex == 4 || comboBox1.SelectedIndex == 5)
comboBox1.SelectedIndex = -1;
}
}
}
Ответы
Ответ 1
Попробуйте это... Это служит вашей цели:
Я предполагаю, что у вас есть комбинированный ComboBox1
и вы хотите отключить второй элемент, то есть элемент с индексом 1.
Установите для свойства DrawMode
значение OwnerDrawFixed
затем обработайте эти два события, как показано ниже:
Font myFont = new Font("Aerial", 10, FontStyle.Regular);
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
if (e.Index == 1) //We are disabling item based on Index, you can have your logic here
{
e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), myFont, Brushes.LightGray, e.Bounds);
}
else
{
e.DrawBackground();
e.Graphics.DrawString(comboBox1.Items[e.Index].ToString(), myFont, Brushes.Black, e.Bounds);
e.DrawFocusRectangle();
}
}
void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedIndex == 1)
comboBox1.SelectedIndex = -1;
}
Ответ 2
Здесь мой ответ основан на 100% Арифа Экбала. Улучшения:
- повторно использовать
Font
из ComboBox вместо создания новых (так что если вы измените его в конструкторе, вам не придется обновлять код) - повторно использовать стандартные
SystemBrushes
(поэтому они должны соответствовать вашей теме; она не будет работать, если вы вручную измените цвета, используемые в ComboBox) - для отключенных предметов мне пришлось перерисовывать фон, иначе каждый раз, когда серые предметы перерисовываются, их цвет становится все ближе и ближе к черному
- создать специальный метод
IsItemDisabled
чтобы избежать копирования/вставки
// Don't forget to change DrawMode, else the DrawItem event won't be called.
// this.comboBox1.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
ComboBox comboBox = (ComboBox)sender;
if (IsItemDisabled(e.Index))
{
// NOTE we must draw the background or else each time we hover over the text it will be redrawn and its color will get darker and darker.
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, SystemBrushes.GrayText, e.Bounds);
}
else
{
e.DrawBackground();
// Using winwaed advice for selected items:
// Set the brush according to whether the item is selected or not
Brush brush = ( (e.State & DrawItemState.Selected) > 0) ? SystemBrushes.HighlightText : SystemBrushes.ControlText;
e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, brush, e.Bounds);
e.DrawFocusRectangle();
}
}
void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (IsItemDisabled(comboBox1.SelectedIndex))
comboBox1.SelectedIndex = -1;
}
bool IsItemDisabled(int index)
{
// We are disabling item based on Index, you can have your logic here
return index % 2 == 1;
}
Ответ 3
Вот еще одна модификация. Проблема с приведенными выше решениями заключается в том, что выбранный элемент не отображается, поскольку передняя часть шрифта и выбор фона являются темными. Следовательно, шрифт должен быть установлен в соответствии со значением e.State
:
private void comboBox1_DrawItem(object sender, DrawItemEventArgs e)
{
ComboBox comboBox = (ComboBox)sender;
if (e.Index >= 0)
{
if (IsItemDisabled(e.Index))
{
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, Brushes.LightSlateGray, e.Bounds);
}
else
{
e.DrawBackground();
// Set the brush according to whether the item is selected or not
Brush br = ( (e.State & DrawItemState.Selected) > 0) ? SystemBrushes.HighlightText : SystemBrushes.ControlText;
e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, br, e.Bounds);
e.DrawFocusRectangle();
}
}
}