【问题标题】:How to show text in combobox when no item selected?未选择项目时如何在组合框中显示文本?
【发布时间】:2011-11-09 11:09:45
【问题描述】:

C# & .Net 2.0 问题(WinForms)

我在ComboBox 中有一组项目,但没有一个被选中。在这种情况下,我想在组合“请选择项目”上显示一个字符串。

当前的实现只是在索引 0 上添加了带有此类文本的空项目,并在用户选择以下项目之一时将其删除。不幸的是,空项目也显示在下拉列表中。如何避免这种情况或以其他方式 - 当没有选择任何项目时,有什么方法可以在 ComboBox 上显示自定义文本?

当ComboBoxStyle 设置为DropDown(ComboBox 是可编辑的)时,以下答案有效。当ComboBoxStyle 设置为DropDownList 时是否有可能这样做?

【问题讨论】:

  • so....当用户在组合框中选择项目时,您不想在项目中显示自定义文本...
  • 我正在寻找适用于 WinForms 而不是 WPF 的解决方案。严格来说,我编辑了第一篇文章并强调了这一点。谢谢。

标签: c# winforms .net-2.0


【解决方案1】:

使用组合框的插入方法将“请选择项目”插入到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;
            }
        }

【讨论】:

  • 但这意味着用户可以选择它。我猜用户希望这显示为提示而不是可选择的答案。
  • 是的,这是我目前的实现,但是这个项目显示在下拉列表中,用户仍然可以选择它。我想避免这种情况,只在组合框上显示文本,而不是在下拉列表中。
  • @skk:由于某种原因,它不起作用。项目已经加载,可能 ToString() 方法具有优先级而不是 Text 属性。
  • @jotb​​ek,不,如果您在 textchanged 事件中编写代码肯定会为您工作。可以贴一下现在修改的代码吗?
  • @skk:如果我错了,请纠正我,但是这段代码会导致无限循环,因为每次更改文本都会触发文本更改事件,并且这段代码会再次运行?
【解决方案2】:

在回复TextBox watermark (CueBanner) which goes away when user types in single line TextBox (not for RichTextBox)时,必须注明IronRazerz。

你需要在你的类中声明以下内容:

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...");

这是假设 Combo Box 的 DropDownStyle 设置为 DropDownList,就像原始发帖人的问题一样。

这应该会产生如下结果:

【讨论】:

  • 这应该是新接受的答案。
【解决方案3】:

我看不到任何本地 .NET 方法可以做到这一点,但如果您想使用底层 Win32 控件来弄脏自己的手...

您应该能够向它发送带有COMBOBOXINFO 结构的CB_GETCOMBOBOXINFO 消息,该结构将包含内部编辑控件的句柄。 然后,您可以向编辑控件发送带有指向字符串的指针的EM_SETCUEBANNER 消息。 (请注意,这至少需要启用 XP 和视觉样式。

【讨论】:

【解决方案4】:
    private void comboBox1_TextChanged(object sender, EventArgs e)
    {
        if (comboBox1.Text == "")
            comboBox1.Text = "Select one of the answers"; 
    }

应该做的伎俩 启动时存在此行,当在组合框中选择一个项目时,将出现此项目文本。删除文本时,该文本将再次出现

【讨论】:

  • 由于某种原因它不起作用。这个解决方案是每个人都在这里建议的解决方案,但是当我设置 Text 属性时,它不会保留传递的值。也许集合中项目的 ToString 方法优先于 Text 属性。
  • 它适用于下拉和简单样式,DropdownList 不起作用。
  • 我宁愿使用 string.Empty 而不是 "" 来创建一个空的文本框。
【解决方案5】:

这就是我的做法。它可能不是最好的方法,并且提供的控制最少;但是,它既简单又快捷,我认为分享它可能是个好主意,以便为其他人提供更多选择。

<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 表示没有进行选择。

【讨论】:

  • 出色的答案。初始选择在第一次选择后消失,并且不会出现在下拉列表中。非常棒的快速解决方案。
  • 是 XAML 吗?问题是关于 Windows 窗体的。
  • @defaultlocale 是的,坦率地说,我不记得为什么我发布了 WPF 答案......一定很累。那是五年前的事了,所以……不记得了。
  • 此答案不适用于 WinForms
【解决方案6】:

将组合框的Dropdownstyle属性设置为Dropdown,并将组合框文本设置为“选择”,如下所示

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

【讨论】:

    【解决方案7】:

    我使用了一个快速的解决方法,所以我可以保持 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;
            }            
        }       
    }
    

    如果您使用数据绑定,则必须创建一个您所绑定类型的虚拟版本 - 只需确保在任何持久性逻辑之前将其删除即可。

    【讨论】:

      【解决方案8】:

      如果以前的解决方案都不适合您,为什么不在组合框上添加一些验证,例如,

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

      【讨论】:

      • 选项 0 表示组合框中的第一个条目。我会使用 -1,这意味着没有选择任何项目。
      【解决方案9】:

      在这里您可以找到 pavlo_ua 创建的解决方案: If you have .Net > 2.0 和 If you have .Net == 2.0 (search for pavlo_ua answer)

      干杯,jbk

      编辑: 所以要得到明确的答案而不仅仅是链接

      当组合框的样式设置为下拉(并且它是可编辑的)时,您可以设置组合框的文本。 当您的 .Net 版本

      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 );
      }
      

      【讨论】:

      • 虽然这在理论上可以回答这个问题,it would be preferable 在此处包含答案的基本部分,并提供链接以供参考。
      • 您可以在组合框的按键事件中使用 e.Handled = true 来防止用户在下拉模式下更改文本
      【解决方案10】:

      表单InitializeComponent();后一行

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

      你只需要一次对吗?如果必须选择,您需要做的就是检查框索引是否为!= -1。任何人都可以详细说明为什么其他答案跳过箍来实现这一点?

      我在这里唯一缺少的就是这个初始文本是灰色的。如果你真的想要,只需在前面使用一个标签,并在索引更改后将其关闭。

      【讨论】:

        【解决方案11】:

        如果ComboBoxStyle 设置为DropDownList,那么确保用户选择项目的最简单方法是设置SelectedIndex = -1,它将为空

        【讨论】:

          【解决方案12】:

          我意识到这是一个旧线程,但只是想让其他可能搜索此问题答案的人知道,在当前版本的 Visual Studio (2015) 中,有一个名为“占位符文本”的属性jotbek最初问的是什么。使用“通用”属性下的“属性”框。

          【讨论】:

          【解决方案13】:

          不幸的是,上述方法都不适合我,所以我在组合框顶部添加了一个标签,上面写着“请选择”。我使用以下代码来显示和隐藏它:

          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();
                }
            }
            

          【讨论】:

            【解决方案14】:

            我也希望找到解决此问题的方法。我看到这是一篇较旧的帖子,但希望我的方法可以为其他人简化这个问题。

            我使用的是下拉样式为 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
                        }
                    }
                }
            

            谢谢

            【讨论】:

              【解决方案15】:

              我无法理解@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;
                      }
                  }
              

              【讨论】:

                【解决方案16】:

                将此类添加到您的解决方案中。重建解决方案后,您将在工具箱中看到 ComboBoxPlus。它适用于组合框的 DropDownStyle 的 DropDownList。尽情享受吧。

                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);
                            }
                        }
                    }
                

                【讨论】:

                • 您应该更多地解释您的解决方案是什么、它是如何工作的和/或它是如何回答问题的。
                【解决方案17】:

                为什么不做 XAML?

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

                【讨论】:

                • 这在 XAML 中无效
                • 我理解你的意思,XAML 更好等等等等。但是当在特定技术中提出问题时,可能有人支持遗留代码并且无法切换或无论如何决定使用该技术。告诉某人使用 xaml 而不是 winforms 就像告诉某人使用 Java 而不是 C#(或任何其他对)。它可能会更好,提供更多帮助等。但不是那么简单,并且没有任何价值作为答案
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2019-04-28
                • 1970-01-01
                • 2011-08-30
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2022-06-10
                相关资源
                最近更新 更多