web-dev-qa-db-fra.com

Comment faire de Combobox dans Winforms en lecture seule

Je ne veux pas que l'utilisateur puisse modifier la valeur affichée dans la liste déroulante. J'utilisais Enabled = false mais le texte est grisé, donc ce n'est pas très lisible. Je veux qu'il se comporte comme une zone de texte avec ReadOnly = true, où le texte est affiché normalement, mais l'utilisateur ne peut pas le modifier.

Y a-t-il un moyen d'accomplir cela?

50
Kishore A

L'article ComboBox-with-read-only-behavior suggère une solution intéressante:

Créez à la fois une zone de texte en lecture seule et une liste déroulante au même endroit. Lorsque vous voulez le mode lecture seule, affichez la zone de texte, lorsque vous souhaitez le modifier, affichez la liste déroulante.

18
Joe

transformez la propriété DropDownStyle en DropDownList au lieu de DropDown puis gérez l'événement TextChanged pour empêcher l'utilisateur de modifier le texte.

140
amar vashi

Je ne sais pas si c'est ce que vous cherchez, mais ...

Définir le DropDownStyle = DropDownList

Puis sur l'événement SelectedIndexChanged

If (ComboBox1.SelectedIndex <> 0)
{
    ComboBox1.SelectedIndex = 0
}

Cette partie laide, c'est qu'ils vont "se sentir" comme s'ils pouvaient le changer. Ils pourraient penser que c'est une erreur, sauf si vous leur donnez une alerte leur indiquant pourquoi ils ne peuvent pas changer la valeur.

10
Dan Williams

La meilleure chose que je puisse suggérer est de remplacer la liste déroulante par une zone de texte en lecture seule (ou peut-être simplement une étiquette) - de cette façon, l'utilisateur peut toujours sélectionner/copier la valeur, etc.

Bien sûr, une autre tactique effrontée consisterait à définir DropDownStyle sur DropDownList et à supprimer toutes les autres options - l'utilisateur n'aura plus rien à choisir ;-p

8
Marc Gravell

entrez la description du lien ici

Il suffit de changer la DropDownStyle en DropDownList. Ou si vous voulez qu'il soit entièrement en lecture seule, vous pouvez définir Enabled = false, ou si vous n'aimez pas son apparence, j'ai parfois deux commandes, une zone de texte en lecture seule et une liste déroulante, puis masquez la liste déroulante et affichez-la si elle doit être complètement en lecture seule et vice versa.

7
Virus

Je l'ai traitée en sous-classant ComboBox pour ajouter une propriété ReadOnly qui se cache lorsqu'elle est définie et affiche une zone de lecture en lecture seule contenant le même texte:

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

Le code de Michael R fonctionne, mais ...
Le DropDownHeight = 1; doit revenir à la valeur par défaut lorsque la propriété ReadOnly est définie sur false. Donc, insérez avant 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);
        }
    }
}

Pour compléter cette réponse:

Fichier -> Nouveau -> Projet ... Visual C # -> Windows -> Classic Desktop -> Bibliothèque de contrôles Windows Forms

tapez le nom de votre contrôle - OK et collez ce code. 

Vous pouvez choisir le nom de votre fichier dll:
Project - les propriétés de votre projet ... 

  • Nom de l'assembly: tapez le nom. Il suffit de construire la solution et vous avez votre fichier dll. Alors, ouvrez le projet où vous voulez utiliser votre combo Lecture seule, faites un clic droit sur Références 
  • Ajouter une référence ... et parcourez votre fichier dll. Pour insérer votre composant personnalisé dans la boîte à outils, ouvrez votre boîte à outils, cliquez avec le bouton droit sur l'onglet Général -> Choisir des éléments ... 
  • Parcourir votre fichier dll - Ouvrir. Vous pouvez maintenant utiliser votre ReadOnlyComboBox dans vos projets. PS: J'utilise VS2015.
2
Fabio

Voici la meilleure solution pour le Combo ReadOnly.

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

Il supprimera la pression de touche pour le Combo.

2
Manish

Vous pouvez modifier la couleur de couleur de fond et la couleur de fond en couleurs système pour une zone de liste déroulante activée, bien que cela puisse dérouter les utilisateurs (pourquoi l'avoir s'il ne peut pas le changer), cela aura l'air mieux.

1
Tom Anderson

Voici comment vous répondriez qu'une ComboBox avec Enabled = False est difficile à lire:

Un combobox qui a l'air décent quand il est désactivé

1
Neolisk

Définissez la propriété DropdownStyle sur Simple

Ajoutez le code ci-dessous à l'événement KeyPress de ComboBox

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

Ajoutez le code ci-dessous à l'événement KeyDown de ComboBox

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

Si vous l'avez déjà rempli, avez sélectionné l'élément approprié et l'avez défini comme suit DropDownList, vous pouvez utiliser une méthode d'extension de ce type pour réduire rapidement la liste de sélection à l'élément sélectionné:

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

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

Je sais que je suis un peu en retard pour la fête, mais je cherchais cette question précise et je savais qu'il devait y avoir un moyen de rendre le combobox en lecture seule comme s'il s'agissait d'une zone de texte et de désactiver la liste qui apparaît. Ce n'est pas parfait, mais c'est certainement meilleur que toutes les réponses que j'ai trouvées sur Internet et qui ne fonctionnent pas pour moi. Une fois que le bouton est enfoncé et que OnDropDown est appelé, un nouveau thread est créé pour définir la propriété DroppedDown sur false, créant ainsi l'effet de «rien ne se passe». La molette de la souris est utilisée et les événements clés sont également utilisés.

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);
        }
    }
}
0
Michael R

En fait, c'est plutôt 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
0
Rob

Pourquoi n'utilisez-vous pas simplement une zone de texte? Zone de texte a une propriété «Lecture seule», et puisque vous voulez que votre liste déroulante affiche uniquement des données, je ne vois pas pourquoi vous auriez besoin d'une boîte à options.

Une autre solution consiste à annuler l'entrée pour l'événement "à la valeur modifiée". De cette façon, vous ne pourrez plus afficher vos informations quel que soit l'utilisateur ...

0
David Božjak