簡體   English   中英

combobox沒有選中時如何顯示文字?

[英]How to show text in combobox when no item selected?

C# &.Net 2.0 問題 (WinForms)

我在ComboBox中有一組項目,但沒有選擇。 在那種情況下,我想在組合“ Please select item ”上顯示一個字符串。

當前的實現只是在索引0上添加帶有此類文本的空項目,並在用戶 select 以下項目之一時將其刪除。 不幸的是,空項目也顯示在下拉列表中。 如何避免這種情況或以其他方式 - 當沒有選擇任何項目時,有沒有辦法在ComboBox上顯示自定義文本?

ComboBoxStyle設置為DropDownComboBox是可編輯的)時,下面的答案有效。 ComboBoxStyle設置為DropDownList時是否有可能這樣做?

使用組合框的插入方法將“請選擇項目”插入到0索引中,

comboBox1.Items.Insert(0, "Please select any value");

並將所有項目添加到第一個索引之后的組合框。 在表單加載集

comboBox1.SelectedIndex = 0;

編輯:

在表單加載中,通過硬編碼將文本寫入comboBox1.Text

comboBox1.Text = "Please, select any value";

並在 comboBox1 的 TextChanged 事件中編寫以下代碼

 private void comboBox1_TextChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex < 0)
            {
                comboBox1.Text = "Please, select any value";
            }
            else
            {
                comboBox1.Text = comboBox1.SelectedText;
            }
        }

必須將功勞歸功於 IronRazerz ,以響應TextBox 水印 (CueBanner),當用戶在單行 TextBox(不適用於 RichTextBox)中鍵入時,該水印會消失

您需要在類中聲明以下內容:

private const int CB_SETCUEBANNER = 0x1703;

[System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]string lParam);

然后你可以用它來做類似的事情:

SendMessage(this.comboBox1.Handle, CB_SETCUEBANNER, 0, "Please select an item...");

這是假設組合框的DropDownStyle設置為DropDownList ,就像原始海報的問題一樣。

這應該會導致如下結果:

組合框下拉列表的占位符文本

我看不到任何原生的 .NET 方式來做到這一點,但如果你想用底層的 Win32 控件弄臟你的手......

你應該能夠給它發送CB_GETCOMBOBOXINFO與消息COMBOBOXINFO結構,其中將包含內部編輯控件的句柄。 然后,您可以向編輯控件發送帶有指向字符串的指針的EM_SETCUEBANNER消息。 (請注意,這至少需要啟用 XP 和視覺樣式。

    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        if (comboBox1.Text == "")
            comboBox1.Text = "Select one of the answers"; 
    }

應該在啟動時完成此行,當在組合框中選擇一個項目時,將出現此項目文本。 刪除文本時,此文本將再次出現

這是我如何做到的。 它可能不是最好的方法,並且提供的控制最少; 但是,它簡單快捷,我認為分享它可能是個好主意,以便其他人可以使用更多選擇。

<ComboBox SelectedIndex="0">
    <ComboBoxItem Visibility="Collapsed">Please select one...</ComboBoxItem>
    <ComboBoxItem>1</ComboBoxItem>
    <ComboBoxItem>2</ComboBoxItem>
    <ComboBoxItem>3</ComboBoxItem>
    <ComboBoxItem>4</ComboBoxItem>
</ComboBox>

這背后的想法是初始選擇是索引 0,它是折疊的,因此一旦用戶選擇其他內容,它就無法在選擇下使用。 缺點是您必須記住,如果您正在檢查選定的索引,請記住索引 0 表示沒有進行選擇。

我使用了一個快速解決方法,這樣我就可以保持 DropDownList 樣式。

class DummyComboBoxItem
{
    public string DisplayName
    {
        get
        {
            return "Make a selection ...";
        }
    }
}
public partial class mainForm : Form
{
    private DummyComboBoxItem placeholder = new DummyComboBoxItem();
    public mainForm()
    {
        InitializeComponent();

        myComboBox.DisplayMember = "DisplayName";            
        myComboBox.Items.Add(placeholder);
        foreach(object o in Objects)
        {
            myComboBox.Items.Add(o);
        }
        myComboBox.SelectedItem = placeholder;
    }

    private void myComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (myComboBox.SelectedItem == null) return;
        if (myComboBox.SelectedItem == placeholder) return;            
        /*
            do your stuff
        */
        myComboBox.Items.Add(placeholder);
        myComboBox.SelectedItem = placeholder;
    }

    private void myComboBox_DropDown(object sender, EventArgs e)
    {
        myComboBox.Items.Remove(placeholder);
    }

    private void myComboBox_Leave(object sender, EventArgs e)
    {
        //this covers user aborting the selection (by clicking away or choosing the system null drop down option)
        //The control may not immedietly change, but if the user clicks anywhere else it will reset
        if(myComboBox.SelectedItem != placeholder)
        {
            if(!myComboBox.Items.Contains(placeholder)) myComboBox.Items.Add(placeholder);
            myComboBox.SelectedItem = placeholder;
        }            
    }       
}

如果您使用數據綁定,您將必須創建一個您綁定的類型的虛擬版本 - 只需確保在任何持久性邏輯之前將其刪除。

將組合框的 Dropdownstyle 屬性設置為 Dropdown 並將組合框文本設置為“選擇”,如下所示

            combobox.DataSource = dsIn.Tables[0];
            combobox.DisplayMember = "Name";
            combobox.ValueMember = "Value";
            combobox.Text = "--Select--";

表格InitializeComponent();后一行InitializeComponent();

cbo_MyDropBox.Text = "Select a server...";

你只需要一次吧? 如果選擇是強制性的,您需要做的就是檢查框索引是否為!= -1 任何人都可以詳細說明為什么其他答案跳過箍來實現這一目標?

我在這里唯一缺少的就是這個初始文本變灰了。 如果您真的想要,只需在前面使用一個標簽,並在索引更改后將其關閉。

如果以前的解決方案都不適合您,為什么不在組合框上添加一些驗證,例如,

    var orginalindex = 0;

    private void comboBox1_SelectedItemChanged(object sender, EventArgs e)
    {
        if (comboBox1.SelectedIndex == 0)
        {
            comboBox1.Text = "Select one of the answers";
            comboBox1.SelectedIndex = comboBox1.SelectedIndex;
        }
        else
        {
            orginalindex = comboBox1.SelectedIndex;
        }
    }

在這里您可以找到由 pavlo_ua 創建的解決方案: 如果您有 .Net > 2.0並且如果您有 .Net == 2.0(搜索 pavlo_ua 答案)

干杯,jbk

編輯:所以要有明確的答案,而不僅僅是鏈接

當組合框的樣式設置為 DropDown(並且它是可編輯的)時,您可以設置組合框的文本。 當您的 .Net 版本 < 3.0 時,沒有 IsReadonly 屬性,因此我們需要使用 win api 將組合框的文本框設置為只讀:

private bool m_readOnly = false;
private const int EM_SETREADONLY = 0x00CF;

internal delegate bool EnumChildWindowsCallBack( IntPtr hwnd, IntPtr lParam );

[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

[ DllImport( "user32.dll" ) ]
internal static extern int EnumChildWindows( IntPtr hWndParent, EnumChildWindowsCallBack lpEnumFunc, IntPtr lParam );


private bool EnumChildWindowsCallBackFunction(IntPtr hWnd, IntPtr lparam)
{
      if( hWnd != IntPtr.Zero )
       {
              IntPtr readonlyValue = ( m_readOnly ) ? new IntPtr( 1 ) : IntPtr.Zero;
             SendMessage( hWnd, EM_SETREADONLY, readonlyValue, IntPtr.Zero );
             comboBox1.Invalidate();
             return true;
       }
       return false;
}

private void MakeComboBoxReadOnly( bool readOnly )
{
    m_readOnly = readOnly;
    EnumChildWindowsCallBack callBack = new EnumChildWindowsCallBack(this.EnumChildWindowsCallBackFunction );
    EnumChildWindows( comboBox1.Handle, callBack, IntPtr.Zero );
}

如果ComboBoxStyle設置為DropDownList則確保用戶選擇項目的最簡單方法是設置SelectedIndex = -1 ,它將為空

我意識到這是一個舊線程,但只是想讓其他可能搜索這個問題的答案的人知道,在當前版本的 Visual Studio(2015)中,有一個名為“Placeholder Text”的屬性,它最初執行 jotbek問了。 使用“通用”屬性下的“屬性”框。

不幸的是,以上都不適合我,所以我在組合框頂部添加了一個標簽,上面寫着“請選擇”。 我使用以下代碼來顯示和隱藏它:

  1. 當我初始化我的組合框時,如果沒有選定的值,我將它放在前面並設置文本:

     PleaseSelectValueLabel.BringToFront(); PleaseSelectValueLabel.Text = Constants.AssessmentValuePrompt;
  2. 如果選擇了一個值,我會將其發送到后面:

     PleaseSelectValueLabel.SendToBack();
  3. 然后我使用以下事件將標簽移到前面或后面,具體取決於用戶是否選擇了一個值:

     private void PleaseSelectValueLabel_Click(object sender, EventArgs e) { PleaseSelectValueLabel.SendToBack(); AssessmentValue.Focus(); } private void AssessmentValue_Click(object sender, EventArgs e) { PleaseSelectValueLabel.SendToBack(); } //if the user hasnt selected an item, make the please select label visible again private void AssessmentValue_Leave(object sender, EventArgs e) { if (AssessmentValue.SelectedIndex < 0) { PleaseSelectValueLabel.BringToFront(); } }

我也希望找到解決方案。 我看到這是一篇較舊的帖子,但希望我的方法可以為其他人簡化這個問題。

我使用的是下拉樣式為 DropDownList 的組合框,但這應該適用於其他樣式。 在我的情況下,我希望文本閱讀“選擇源”,我希望其他選項是“文件”和“文件夾”

comboBox1.Items.AddRange(new string[] {"Select Source", "File", "Folder" });
comboBox1.Text = "Select Source";

如果您願意,可以改為選擇 0 索引。 然后,當索引更改時,我刪除了“選擇源”項,因為該文本是否可見不再重要。

comboBox1.SelectedIndexChanged += new EventHandler(comboBox1_IndexChanged);

private void comboBox1_IndexChanged(object sender, EventArgs e)
    {
        comboBox1.Items.Remove("Select Source");
        if (comboBox1.SelectedIndex != -1)
        {
            if (comboBox1.SelectedIndex == 0) // File
            {
                // Do things
            }
            else if (comboBox1.SelectedIndex == 1) // Folder
            {
                // Do things
            }
        }
    }

謝謝

這適用於DropDownList樣式 - 創建一個派生自ComboBox的類
(將在重建后顯示在工具箱中)使用System.Drawing繪制提示,
將此控件從工具箱放置到您的表單並在其屬性中設置提示“請選擇項目”。

public class HintComboBox : ComboBox
{
    string hint;
    public string Hint
    {
        get { return hint; }
        set { hint = value; Invalidate(); }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);
        if (m.Msg == 0xf && !Focused && string.IsNullOrEmpty(Text) && !string.IsNullOrEmpty(Hint))
           using (var g = CreateGraphics())
           {
               TextRenderer.DrawText(g, Hint, Font, ClientRectangle, SystemColors.GrayText, BackColor,
                                    TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter);
           }
    }
}

我無法獲得 @Andrei Karcheuski 的工作方法,但他啟發了我采用這種方法:(我添加了 Localizable 屬性,以便可以通過 .resx 文件為您使用它的每個對話框翻譯提示)

 public partial class HintComboBox : ComboBox
{
    string hint;
    Font greyFont;

    [Localizable(true)]
    public string Hint
    {
        get { return hint; }
        set { hint = value; Invalidate(); }
    }

    public HintComboBox()
    {
        InitializeComponent();
    }

    protected override void OnCreateControl()
    {
        base.OnCreateControl();

        if (string.IsNullOrEmpty(Text))
        {
            this.ForeColor = SystemColors.GrayText;
            Text = Hint;
        }
        else
        {
            this.ForeColor = Color.Black;
        }
    }

    private void HintComboBox_SelectedIndexChanged(object sender, EventArgs e)
    {
        if( string.IsNullOrEmpty(Text) )
        {
            this.ForeColor = SystemColors.GrayText;
            Text = Hint;
        }
        else
        {
            this.ForeColor = Color.Black;
        }
    }

將此 class 添加到您的解決方案中。 重建解決方案后,您將在工具箱中看到 ComboBoxPlus。 它適用於 DropDownList for DropDownStyle of comboBox。享受它。

class ComboBoxPlus : System.Windows.Forms.ComboBox
    {
        private const int CB_SETCUEBANNER = 0x1703;

        [System.Runtime.InteropServices.DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
        private static extern int SendMessage(System.IntPtr hWnd, int msg, int wParam, [System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.LPWStr)]string lParam);

        private string placeholder = string.Empty;
        public string Placeholder
        {
            get { return placeholder; }
            set
            {
                placeholder = value;
                SendMessage(Handle, CB_SETCUEBANNER, 0, Placeholder);
            }
        }
    }

為什么不做 XAML?

<ComboBox x:Name="myComboBoxMenu" PlaceholderText="Hello"/>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM