简体   繁体   English

如何使winforms中的组合框只读

[英]How to make Combobox in winforms readonly

I do not want the user to be able to change the value displayed in the combobox.我不希望用户能够更改组合框中显示的值。 I have been using Enabled = false but it grays out the text, so it is not very readable.我一直在使用Enabled = false但它使文本变灰,所以它不是很可读。 I want it to behave like a textbox with ReadOnly = true , where the text is displayed normally, but the user can't edit it.我希望它表现得像一个带有ReadOnly = true的文本框,文本正常显示,但用户无法编辑它。

Is there is a way of accomplishing this?有没有办法做到这一点?

DropDownStyle属性设置为DropDownList而不是DropDown然后处理TextChanged事件以防止用户更改文本。

The article ComboBox-with-read-only-behavior suggests an interesting solution:文章ComboBox-with-read-only-behavior提出了一个有趣的解决方案:

Create both a readonly textbox and a combobox in the same place.在同一位置创建只读文本框和组合框。 When you want readonly mode, display the textbox, when you want it to be editable, display the combobox.当你想要只读模式时,显示文本框,当你想要它可编辑时,显示组合框。

Not sure if this is what you're looking for but...不确定这是否是您要找的东西,但是...

Set the DropDownStyle = DropDownList设置 DropDownStyle = DropDownList

Then on the SelectedIndexChanged event然后在 SelectedIndexChanged 事件上

if (ComboBox1.SelectedIndex != 0)
{
    ComboBox1.SelectedIndex = 0;
}

This ugly part is that they will "feel" like they can change it.这个丑陋的部分是他们会“感觉”他们可以改变它。 They might think this is an error unless you give them an alert telling them why they can't change the value.他们可能会认为这是一个错误,除非您向他们发出警报,告诉他们为什么无法更改该值。

enter link description here在此处输入链接描述

Just change the DropDownStyle to DropDownList .只需将DropDownStyle更改为DropDownList Or if you want it completely read only you can set Enabled = false , or if you don't like the look of that I sometimes have two controls, one readonly textbox and one combobox and then hide the combo and show the textbox if it should be completely readonly and vice versa.或者,如果您希望它完全只读,您可以设置Enabled = false ,或者如果您不喜欢它的外观,我有时会使用两个控件,一个只读文本框和一个组合框,然后隐藏组合并显示文本框(如果应该)完全只读,反之亦然。

The best thing I can suggest is to replace the combo-box with a read-only textbox (or just perhaps a label) - that way the user can still select/copy the value, etc.我能建议的最好的事情是用只读文本框(或者只是一个标签)替换组合框 - 这样用户仍然可以选择/复制值等。

Of course, another cheeky tactic would be to set the DropDownStyle to DropDownList , and just remove all other options - then the user has nothing else to pick ;-p当然,另一种厚颜无耻的策略是将DropDownStyle设置为DropDownList ,然后删除所有其他选项 - 然后用户没有其他选择;-p

I've handled it by subclassing the ComboBox to add a ReadOnly property that hides itself when set and displays a ReadOnly TextBox on top containing the same Text:我已经通过继承 ComboBox 添加一个 ReadOnly 属性来处理它,该属性在设置时隐藏自己并在顶部显示一个包含相同文本的 ReadOnly TextBox:

class ComboBoxReadOnly : ComboBox
{
    public ComboBoxReadOnly()
    {
        textBox = new TextBox();
        textBox.ReadOnly = true;
        textBox.Visible = false;
    }

    private TextBox textBox;

    private bool readOnly = false;

    public bool ReadOnly
    {
        get { return readOnly; }
        set
        {
            readOnly = value;

            if (readOnly)
            {
                this.Visible = false;
                textBox.Text = this.Text;
                textBox.Location = this.Location;
                textBox.Size = this.Size;
                textBox.Visible = true;

                if (textBox.Parent == null)
                    this.Parent.Controls.Add(textBox);
            }
            else
            {
                this.Visible = true;
                this.textBox.Visible = false;
            }
        }
    }
}

Here is the Best solution for the ReadOnly Combo.这是 ReadOnly Combo 的最佳解决方案。

private void combo1_KeyPress(object sender, KeyPressEventArgs e)
{
    e.KeyChar = (char)Keys.None;
}

It will discard the keypress for the Combo.它将丢弃 Combo 的按键。

Michael R's code works, but... Michael R 的代码有效,但是...
The DropDownHeight = 1; DropDownHeight = 1; must be back to the default value when ReadOnly property is set to false.当 ReadOnly 属性设置为 false 时,必须恢复为默认值。 So, insert before base.OnDropDown(e) : DropDownHeight = 106;所以,在base.OnDropDown(e)之前插入: DropDownHeight = 106;

using System;
using System.Threading;
using System.Windows.Forms;

namespace Test_Application
{
    class ReadOnlyComboBox : ComboBox
    {
        private bool _readOnly;
        private bool isLoading;
        private bool indexChangedFlag;
        private int lastIndex = -1;
        private string lastText = "";

        public ReadOnlyComboBox()
        {
        }

        public bool ReadOnly
        {
            get { return _readOnly; }
            set { _readOnly = value; }
        }

        protected override void OnDropDown (EventArgs e)
        {
            if (_readOnly)
            {
                DropDownHeight = 1;
                var t = new Thread(CloseDropDown);
                t.Start();
                return;
            }
            DropDownHeight = 106; //Insert this line.
            base.OnDropDown(e);
        }

        private delegate void CloseDropDownDelegate();
        private void WaitForDropDown()
        {
            if (InvokeRequired)
            {
                var d = new CloseDropDownDelegate (WaitForDropDown);
                Invoke(d);
            }
            else
            {
                DroppedDown = false;
            }
        }
        private void CloseDropDown()
        {
            WaitForDropDown();
        }

        protected override void OnMouseWheel (MouseEventArgs e)
        {
            if (!_readOnly) 
                base.OnMouseWheel(e);
        }

        protected override void OnKeyDown (KeyEventArgs e)
        {
            if (_readOnly)
            {
                switch (e.KeyCode)
                {
                    case Keys.Back:
                    case Keys.Delete:
                    case Keys.Up:
                    case Keys.Down:
                        e.SuppressKeyPress = true;
                        return;
                }
            }
            base.OnKeyDown(e);
        }

        protected override void OnKeyPress (KeyPressEventArgs e)
        {
            if (_readOnly)
            {
                e.Handled = true;
                return;
            }
            base.OnKeyPress(e);
        }
    }
}

To complete this answer:要完成此答案:

File -> New -> Project... Visual C# -> Windows -> Classic Desktop -> Windows Forms Control Library文件 -> 新建 -> 项目... Visual C# -> Windows -> 经典桌面 -> Windows 窗体控件库

type the Name of your control - OK and paste this code.输入控件的名称 - 确定并粘贴此代码。

You can choose the name of your dll file:您可以选择 dll 文件的名称:
Project - yourproject Properties...项目 - 您的项目属性...

  • Assembly name: type the name.程序集名称:键入名称。 Just build the solution and you have your dll file.只需构建解决方案,您就拥有了 dll 文件。 So, open the project where you want to use your Read Only combo, right click on References因此,打开要使用只读组合的项目,右键单击“引用”
  • Add Reference... and browse your dll file.添加参考...并浏览您的 dll 文件。 To Insert your custom component into Toolbox, open your Toolbox, right click on General tab -> Choose Items...要将您的自定义组件插入工具箱,请打开您的工具箱,右键单击常规选项卡 -> 选择项目...
  • Browse your dll file - Open.浏览您的 dll 文件 - 打开。 Now you can use your ReadOnlyComboBox in your projects.现在您可以在您的项目中使用您的 ReadOnlyComboBox。 PS: I'm using VS2015. PS:我使用的是 VS2015。

This is how you would address the fact that a ComboBox with Enabled = False is hard to read:这是您将如何解决具有Enabled = FalseComboBox难以阅读的事实:

A combobox that looks decent when it is disabled 禁用时看起来不错的组合框

您可以将前景色和背景色更改为已启用组合框的系统颜色,尽管这可能会使用户感到困惑(如果他们不能更改它,为什么要使用它),但它看起来会更好。

Actually, its rather simple:其实很简单:

Private Sub combobox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles combobox1.KeyDown
    ' the following makes this the combobox read only    
    e.SuppressKeyPress = True    
End Sub

Set DropdownStyle Property to SimpleDropdownStyle属性设置为Simple

Add below code to to KeyPress event of ComboBox将以下代码添加到 ComboBox 的KeyPress事件

private void comboBoxName_KeyPress(object sender, KeyPressEventArgs e)
{
    e.Handled = true;
    return;
}

Add below code to to KeyDown event of ComboBox将以下代码添加到 ComboBox 的KeyDown事件

private void comboBoxName_KeyDown(object sender, KeyEventArgs e)
{
    e.Handled = true;
    return;
}

If you've already populated it, and selected the appropriate item, and made it a DropDownList , then you can use an extension method like this to quickly reduce the selection list down to just the selected item:如果您已经填充了它,并选择了适当的项目,并将其设为DropDownList ,那么您可以使用这样的扩展方法来快速将选择列表缩小到选定的项目:

public static void MakeReadOnly(this ComboBox pComboBox) {
   if (pComboBox.SelectedItem == null)
      return;

   pComboBox.DataSource = new List<object> {
      pComboBox.SelectedItem
   };
}

I know that I'm a little late to the party, but I was researching this exact question and I knew that there had to be some way to make the combobox readonly as if it were a textbox and disabled the list popping up.我知道我参加聚会有点晚了,但我正在研究这个确切的问题,我知道必须有某种方法使组合框只读,就好像它是一个文本框并禁用列表弹出。 It's not perfect, but it is definitely better than all of the answers I've been finding all over the internet that don't work for me.它并不完美,但绝对比我在互联网上找到的所有对我都不起作用的答案要好。 After the button is pressed and the OnDropDown is called, a new thread is created that will set the DroppedDown property to false, thus creating the effect of "nothing happening."按下按钮并调用 OnDropDown 后,将创建一个新线程,将 DroppedDown 属性设置为 false,从而产生“什么也没有发生”的效果。 The mouse wheel is consumed and key events are consumed as well.鼠标滚轮被消耗,按键事件也被消耗。

using System;
using System.Threading;
using System.Windows.Forms;

namespace Test_Application
{
    class ReadOnlyComboBox : ComboBox
    {
        private bool _readOnly;
        private bool isLoading;
        private bool indexChangedFlag;
        private int lastIndex = -1;
        private string lastText = "";

        public ReadOnlyComboBox()
        {
        }

        public bool ReadOnly
        {
            get { return _readOnly; }
            set { _readOnly = value; }
        }

        protected override void OnDropDown(EventArgs e)
        {
            if (_readOnly)
            {
                DropDownHeight = 1;
                var t = new Thread(CloseDropDown);
                t.Start();
                return;
            }
            base.OnDropDown(e);
        }

        private delegate void CloseDropDownDelegate();
        private void WaitForDropDown()
        {
            if (InvokeRequired)
            {
                var d = new CloseDropDownDelegate(WaitForDropDown);
                Invoke(d);
            }
            else
            {
                DroppedDown = false;
            }
        }
        private void CloseDropDown()
        {
            WaitForDropDown();
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            if (!_readOnly) 
                base.OnMouseWheel(e);
        }

        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (_readOnly)
            {
                switch (e.KeyCode)
                {
                    case Keys.Back:
                    case Keys.Delete:
                    case Keys.Up:
                    case Keys.Down:
                        e.SuppressKeyPress = true;
                        return;
                }
            }
            base.OnKeyDown(e);
        }

        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (_readOnly)
            {
                e.Handled = true;
                return;
            }
            base.OnKeyPress(e);
        }
    }
}

Simplest way in code :代码中最简单的方法

instead of adding methods for KeyPress or KeyDown , add this code on ' Form1_Load ' method:不要为KeyPressKeyDown添加方法,而是在“ Form1_Load ”方法上添加此代码:

comboBox1.KeyPress += (sndr, eva) => eva.Handled = true;

or

comboBox1.KeyDown += (sndr, eva) => eva.SuppressKeyPress = true;

(sndr, eva) is for (object sender, EventArgs e) (sndr, eva)用于(object sender, EventArgs e)

Why don't you just use a text box?为什么不直接使用文本框? Text box has a "Read only" property, and since you want your combo box only to display data, I don't see why you would need a combo box.文本框具有“只读”属性,并且由于您希望组合框仅显示数据,因此我不明白您为什么需要组合框。

An alternative is that you just cancel out the input for the "on value changed" event.另一种方法是您只需取消“on value changed”事件的输入。 That way you will be displaying your information no mater what user does ...这样,无论用户做什么,您都将显示您的信息......

I dont know if that is what you are looking but this prevents the user from chosing any item from the drop down and still be able to type text in the combobox.我不知道这是否是您要查找的内容,但这会阻止用户从下拉列表中选择任何项目并且仍然能够在组合框中键入文本。 If you dont want the user to type text in the combobox you can make it Dropdown list from the properties menu.如果您不希望用户在组合框中键入文本,您可以从属性菜单中将其设为下拉列表。

So you get Read Only combobox .所以你得到Read Only 组合框

  1. On Selected Index Changed选定索引已更改
  2. Make the selected Index -1 " comboBox.SelectedIndex = -1 ";使选定的索引 -1 " comboBox.SelectedIndex = -1 ";

     private void MyComboBox_comboBox_SelectedIndexChanged(object sender, EventArgs e) { MyComboBox_comboBox.SelectedIndex = -1; }

Here is the Best solution for the ReadOnly Combo.这是 ReadOnly Combo 的最佳解决方案。

private void combo1_KeyPress(object sender, KeyPressEventArgs e) {
    e.KeyChar = (char)Keys.None; 
} 

It will discard the keypress for the Combo.它将丢弃 Combo 的按键。 It doesn't have "e. KeyChar " !它没有“e. KeyChar ”!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM