C# 禁用组合框中的特定项目

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11445125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 17:52:44  来源:igfitidea点击:

Disabling particular Items in a Combobox

c#winformscombobox

提问by Mark Kram

I have a WinForms App and I was wondering if there was a more elegant way of disabling Combobox item without changing the SelectedIndex property -1 for all disabled values.

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

I have been googling and a lot of the solutions involve ASP.Net DropDownLists but this LINKlooks promising. I think I may have to build my own ComboBox control but before I re-invent the wheel I figure I would ask here if it was possible.

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

UPDATE

更新

Here is the final solution, thanks to Arif Eqbal:

这是最终的解决方案,感谢 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;
            }
        }
    }

采纳答案by Arif Eqbal

Try this... Does it serve your purpose:

试试这个......它是否符合您的目的:

I assume you have a combobox called ComboBox1and you want to disable the second item i.e. an item with index 1.

我假设您有一个名为的组合框,ComboBox1并且您想禁用第二个项目,即索引为 1 的项目。

Set the DrawModeproperty of the combobox to OwnerDrawFixedthen handle these two events as shown below:

设置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;
}

回答by user276648

Here's my answer based 100% on Arif Eqbal's. The improvements are:

这是我 100% 基于 Arif Eqbal 的答案。改进之处是:

  • reuse the Fontfrom the ComboBox instead of creating new ones (so that if you change it in the designer, you won't have to update the code)
  • reuse the default SystemBrushes(so it should match your theme ; it won't work if you manually change the colors used in the ComboBox though)
  • for the disabled items I had to redraw the background, else each time the grayed items are redrawn, their color get closer and closer to black
  • create a dedicated IsItemDisabledmethod to avoid copy/paste
  • 重用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'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;
}

回答by winwaed

Here's a further modification. The problem with the above solutions is that a selected item isn't visible because the font foreground and the background selection are both dark. Hence the font should be set according to the value of e.State:

这是进一步的修改。上述解决方案的问题是所选项目不可见,因为字体前景和背景选择都是黑色的。因此字体应根据 的值设置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();
            }
        }
    }