[c#] Disabilitazione di elementi particolari in una casella combinata



Answers

Ecco la mia risposta basata al 100% su Arif Eqbal. I miglioramenti sono:

  • riutilizzare il Font dal ComboBox invece di crearne di nuovi (in modo che se lo si cambia nel designer, non sarà necessario aggiornare il codice)
  • riutilizzare i SystemBrushes default (quindi dovrebbe corrispondere al tema, ma non funzionerà se si modificano manualmente i colori utilizzati nel ComboBox)
  • per gli elementi disabilitati ho dovuto ridisegnare lo sfondo, altrimenti ogni volta che gli elementi in grigio vengono ridisegnati, il loro colore si avvicina sempre di più al nero
  • creare un metodo IsItemDisabled dedicato per evitare il copia / incolla
// 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();
        e.Graphics.DrawString(comboBox.Items[e.Index].ToString(), comboBox.Font, SystemBrushes.ControlText, 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;
}
Question

Ho una App WinForms e mi chiedevo se esistesse un modo più elegante di disabilitare l'elemento Combobox senza modificare la proprietà SelectedIndex -1 per tutti i valori disabilitati.

Sono stato google e molte delle soluzioni coinvolgono ASP.Net DropDownLists ma questo LINK sembra promettente. Penso che potrei dover costruire il mio controllo ComboBox ma prima di re-inventare la ruota credo di chiedere se fosse possibile.

AGGIORNARE

Ecco la soluzione finale, grazie a 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;
            }
        }
    }



Links