2012-07-12 13 views
15

Ho un'app WinForms e mi chiedevo se esistesse un modo più elegante di disabilitare la voce Combobox senza modificare la proprietà SelectedIndex -1 per tutti i valori disabilitati.Disattivazione di elementi particolari in una casella combinata

Ho cercato su google e molte 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.

UPDATE

Ecco la soluzione definitiva, 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; 
      } 
     } 
    } 
+3

ASP.NET = WinForms, non guardare lì. Estendere il ComboBox di base non è terribilmente difficile (di solito fatto per aggiungere checkbox o icone o quant'altro), ma non credo che ci sia un supporto standard di questo tipo. –

+1

Il link che hai menzionato è la strada da percorrere se vuoi davvero dare agli utenti la sensazione che l'oggetto sia disabilitato. Potresti voler disegnare il testo in grigio, potresti non voler mostrare una selezione di backcolor e così via e, naturalmente, l'utente può comunque selezionare quell'elemento in modo da avere ovviamente bisogno di gestire selectedIndexChanged e impostare l'indice selezionato su -1. Ma sarà visivamente più suggestivo fare l'esercizio. –

risposta

23

Prova questo ... vuol servire il vostro scopo:

presumo si dispone di una casella combinata chiamato ComboBox1 e si desidera disabilitare il secondo elemento, ad esempio un articolo con indice 1.

Impostare la proprietà DrawMode del comboBox a OwnerDrawFixed poi gestire questi due eventi come illustrato di seguito:

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

Il mio amico è un genio, grazie! –

11

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

  • riutilizzare il Font dalla casella combinata, invece di crearne di nuovi (in modo che se si modifica nella finestra di progettazione, non sarà necessario aggiornare il codice)
  • riutilizzare il default SystemBrushes (quindi dovrebbe corrispondere al tuo tema, ma non funzionerà se cambi manualmente i colori usati nel ComboBox)
  • per gli elementi disabilitati Ho dovuto ridisegnare lo sfondo, altrimenti ogni volta che gli elementi in grigio sono ridisegnati, il loro colore avvicinarsi sempre di più al nero
  • creare un dedicato IsItemDisabled m etodo per evitare 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; 
} 
4

Ecco una ulteriore modifica. Il problema con le soluzioni di cui sopra è che un elemento selezionato non è visibile perché il carattere in primo piano e la selezione dello sfondo sono entrambi scuri. Da qui il carattere deve essere impostato in base al valore di 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(); 
      } 
     } 
    } 
Problemi correlati