2012-07-12 13 views
15

Tôi có một ứng dụng WinForms và tôi đã tự hỏi nếu có một cách thanh lịch hơn vô hiệu hóa mục Combobox mà không thay đổi thuộc tính SelectedIndex -1 cho tất cả các giá trị vô hiệu hóa.Vô hiệu hóa các mục cụ thể trong một Combobox

Tôi đã googling và rất nhiều giải pháp liên quan đến ASP.Net DropDownLists nhưng điều này LINK trông đầy hứa hẹn. Tôi nghĩ rằng tôi có thể phải xây dựng kiểm soát ComboBox của riêng tôi nhưng trước khi tôi tái phát minh ra bánh xe tôi hình tôi sẽ yêu cầu ở đây nếu nó có thể.

CẬP NHẬT

Dưới đây là giải pháp cuối cùng, nhờ 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, đừng tìm ở đó. Mở rộng ComboBox cơ bản không phải là khó khăn khủng khiếp (thường được thực hiện để thêm các hộp kiểm hoặc biểu tượng hoặc whatnot), nhưng tôi không nghĩ rằng có bất kỳ hỗ trợ tiêu chuẩn như vậy. –

+1

Liên kết bạn đã đề cập là cách để đi nếu bạn thực sự muốn mang đến cho người dùng cảm giác về mục bị vô hiệu hóa. Bạn có thể muốn vẽ văn bản màu xám, bạn có thể muốn không hiển thị backcolor lựa chọn và vân vân và dĩ nhiên người dùng vẫn có thể chọn mục đó, do đó bạn sẽ cần xử lý selectedIndexChanged và thiết lập selectedIndex thành -1. Nhưng nó sẽ trực quan hơn để làm bài tập. –

Trả lời

23

Hãy thử điều này ... nó phục vụ mục đích của bạn:

Tôi giả sử bạn có một combobox được gọi là ComboBox1 và bạn muốn vô hiệu hóa mục thứ hai tức là một mục có chỉ mục 1.

Đặt thuộc tính DrawMode của comboBox đến OwnerDrawFixed sau đó xử lý hai sự kiện này như được hiển thị bên dưới:

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

Bạn của tôi là một thiên tài, cảm ơn bạn! –

11

Đây là câu trả lời của tôi dựa trên 100% trên Arif Eqbal's. Những cải tiến bao gồm:

  • tái sử dụng các Font từ ComboBox thay vì tạo ra những cái mới (do đó nếu bạn thay đổi nó trong thiết kế, bạn sẽ không cần phải cập nhật mã)
  • tái sử dụng mặc định SystemBrushes (do đó, nó sẽ phù hợp với chủ đề của bạn; nó sẽ không hoạt động nếu bạn thay đổi màu sắc theo cách thủ công trong ComboBox)
  • cho các mục bị vô hiệu hóa Tôi phải vẽ lại nền, mỗi khi các mục màu xám được vẽ lại, màu của chúng đến gần hơn và gần hơn với màu đen
  • tạo ra một IsItemDisabled m chuyên dụng ethod để tránh sao chép/dán

// 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

Dưới đây là một chỉnh sửa thêm. Vấn đề với các giải pháp trên là một mục đã chọn không hiển thị vì phông chữ nền trước và chọn nền đều tối. Do đó, phông chữ nên được đặt theo giá trị của 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(); 
      } 
     } 
    }