【问题标题】:Disabling particular Items in a Combobox禁用组合框中的特定项目
【发布时间】:2012-07-11 19:22:25
【问题描述】:

我有一个 WinForms 应用程序,我想知道是否有更优雅的方式来禁用 Combobox 项,而无需更改所有禁用值的 SelectedIndex 属性 -1。

我一直在谷歌搜索,很多解决方案都涉及 ASP.Net DropDownLists,但这个LINK 看起来很有希望。我想我可能必须构建自己的 ComboBox 控件,但在我重新发明轮子之前,我想我会在这里询问是否可能。

更新

感谢 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;
            }
        }
    }

【问题讨论】:

  • ASP.NET != WinForms,别看那里。扩展基本的 ComboBox 并不难(通常是为了添加复选框或图标等),但我认为没有这样的标准支持。
  • 如果您真的想让用户感觉到该项目被禁用,那么您提到的链接就是您要走的路。您可能希望将文本绘制为灰色,您可能希望不显示选择背景色等,当然用户仍然可以选择该项目,因此您当然需要处理 selectedIndexChanged 并将 selectedIndex 设置为 -1。但做这个练习在视觉上会更有启发性。

标签: c# winforms combobox


【解决方案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% 基于 Arif Eqbal 的答案。 改进如下:

    • 重用 ComboBox 中的 Font 而不是创建新的(这样,如果您在设计器中更改它,您就不必更新代码)
    • 重用默认的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's 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;
    }
    

    【讨论】:

    • @cool_php 我已经有一段时间没有使用该代码了。代码开头的注释还不够,即使用OwnerDrawFixed
    【解决方案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();
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多