20

私は WinForms アプリを持っていますが、すべての無効な値に対して SelectedIndex プロパティ -1 を変更せずに Combobox アイテムを無効にするよりエレガントな方法があるかどうか疑問に思っていました。

私はグーグルで検索しており、多くのソリューションには 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;
            }
        }
    }
4

3 に答える 3

32

これを試してください...それはあなたの目的に役立ちますか:

呼び出されたコンボボックスがComboBox1あり、2 番目のアイテム、つまりインデックス 1 のアイテムを無効にしたいとします。

DrawMode以下に示すように、コンボボックスのプロパティを設定して、OwnerDrawFixedこれら 2 つのイベントを処理します。

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;
}
于 2012-07-12T06:39:56.310 に答える
16

これは、Arif Eqbal に 100% 基づいた私の回答です。改善点は次のとおりです。

  • 新しいものを作成する代わりに、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;
}
于 2013-04-05T02:05:01.963 に答える
4

ここでは、さらに変更を加えます。上記の解決策の問題は、フォントの前景と背景の選択が両方とも暗いため、選択した項目が表示されないことです。したがって、フォントは次の値に従って設定する必要があります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();
            }
        }
    }
于 2014-08-11T20:29:36.537 に答える