web-dev-qa-db-fra.com

Comment afficher du texte dans la liste déroulante quand aucun élément n'est sélectionné?

Question C # & .Net 2.0 (WinForms)

J'ai défini des éléments dans ComboBox et aucun d'entre eux n'est sélectionné. Je voudrais montrer une chaîne sur le combo " Veuillez sélectionner l'item " dans cette situation. 

L’implémentation actuelle vient d’être ajoutée à un élément vide avec un tel texte sur l’index 0 et le supprimer lorsque l’utilisateur sélectionne l’un des éléments suivants. Malheureusement, les éléments vides sont également affichés dans la liste déroulante. Comment éviter cette situation ou d'une autre manière - existe-t-il un moyen d'afficher du texte personnalisé sur ComboBox lorsqu'aucun élément n'est sélectionné?

Les réponses ci-dessous fonctionnent lorsque ComboBoxStyle est défini sur DropDown (ComboBox est modifiable). Est-il possible de faire cela lorsque ComboBoxStyle est défini sur DropDownList?

20
jotbek

Ici vous pouvez trouver une solution créée par pavlo_ua: Si vous avez .Net> 2.0 et Si vous avez .Net == 2.0 (recherchez pavlo_ua answer)

À la vôtre, jbk

edit: Donc, pour avoir une réponse claire et pas seulement un lien

Vous pouvez définir Text of combobox lorsque son style est défini sur DropDown (et qu'il est modifiable) . Lorsque vous avez la version .Net <3.0, il n'y a pas de propriété IsReadonly; :

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

Utilisez la méthode d'insertion de la liste déroulante pour insérer le "Veuillez sélectionner l'élément" dans l'index 0, 

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

et ajoutez tous les éléments à la liste déroulante après le premier index. Dans le jeu de charge 

comboBox1.SelectedIndex = 0;

MODIFIER:

En chargement de formulaire, écrivez le texte dans le comboBox1.Text en codant en dur

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

et dans l'événement TextChanged du comboBox1, écrivez le code suivant

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

Voici comment je le fais. Ce n'est peut-être pas la meilleure méthode et offre le moins de contrôle; Cependant, c'est simple et rapide et j'ai pensé que ce serait une bonne idée de le partager afin que davantage d'options soient disponibles pour les autres.

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

L'idée sous-jacente est que la sélection initiale est l'index 0, qui est réduit, de sorte qu'il n'est pas disponible en sélection pour l'utilisateur une fois qu'il a sélectionné autre chose. L'inconvénient est que vous devez vous rappeler que si vous recherchez un index sélectionné, rappelez-vous que l'index 0 signifie qu'aucune sélection n'a été effectuée.

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

devrait faire l'affaire. Au démarrage, cette ligne est présente. Lorsque vous sélectionnez un élément dans une liste déroulante, le texte de cet élément apparaît. lorsque vous supprimez le texte, ce texte réapparaîtra

3
Moonlight

J'ai utilisé un travail rapide pour conserver le style 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;
        }            
    }       
}

Si vous utilisez la liaison de données, vous devrez créer une version factice du type auquel vous êtes lié. Assurez-vous simplement de la supprimer avant toute logique de persistance.

2
Jesse Adam

Une ligne après le formulaire InitializeComponent();

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

Vous n'en avez besoin qu'une fois, n'est-ce pas? Tout ce que vous devez faire si un choix est obligatoire est de cocher la case index != -1. Quelqu'un pourrait-il expliquer pourquoi les autres réponses sautent à travers des obstacles pour faire avancer les choses? 

La seule chose qui me manque ici, c'est d'avoir ce texte initial grisé. Si vous voulez vraiment utiliser simplement une étiquette devant et l'éteindre une fois l'index modifié.

1
Madmenyo

Définissez la propriété Dropdownstyle de la liste déroulante sur Dropdown et définissez le texte de la liste déroulante sur "Select" comme ci-dessous 

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

Je ne vois aucune méthode native pour le faire, mais si vous voulez vous salir les mains avec les contrôles Win32 sous-jacents ...

Vous devriez pouvoir lui envoyer le message CB_GETCOMBOBOXINFO avec une structure COMBOBOXINFO qui contiendra le handle du contrôle d'édition interne . Vous pourrez ensuite envoyer le message EM_SETCUEBANNER au contrôle d'édition avec un pointeur sur la chaîne . nécessite au moins XP et que les styles visuels soient activés.

1
Deanna

si ComboBoxStyle est défini sur DropDownList, le moyen le plus simple de s'assurer que l'utilisateur sélectionne un élément consiste à définir SelectedIndex = -1, qui sera vide

0
Harry

Cela fonctionne avec le style DropDownList - créer une classe dérivée de ComboBox
(apparaîtra dans la Boîte à outils après la reconstruction) qui dessine le conseil à l’aide de System.Drawing,
Placez ce contrôle de Toolbox dans votre formulaire et définissez le conseil "Veuillez sélectionner un élément" dans ses propriétés.

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);
           }
    }
}
0
Andrei Karcheuski

Je me rends compte que c’est un vieux fil, mais je voulais simplement que les personnes qui cherchaient une réponse à cette question sachent que, dans la version actuelle de Visual Studio (2015), il existe une propriété appelée "Placeholder Text" qui fait ce que jotbek avait à l’origine questionné à propos. Utilisez la boîte de propriétés, sous les propriétés "communes".

0
wheezer

Si aucune des solutions précédentes ne fonctionne pour vous, pourquoi ne pas ajouter une validation sur la liste déroulante, par exemple, 

    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
Ash Burlaczenko

J'espérais trouver une solution à cela aussi. Je vois qu'il s'agit d'un article plus ancien, mais j'espère que mon approche simplifiera le problème pour quelqu'un d'autre.

J'utilisais une liste déroulante avec un style déroulant de DropDownList, mais cela devrait fonctionner avec d'autres styles. Dans mon cas, je voulais que le texte se lise "Sélectionner la source" et que les autres options soient "Fichier" et "Dossier"

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

Vous pouvez sélectionner l'index 0 à la place si vous le souhaitez . J'ai ensuite supprimé l'élément "Sélectionner la source" lorsque l'index est modifié car il n'a plus d'importance si le texte est visible.

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

Merci

0
NAPTlME

Je ne pouvais pas comprendre l’approche de @Andrei Karcheuski au travail mais il m’a inspiré à cette approche:

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

Malheureusement, rien de ce qui précède n'a fonctionné pour moi. J'ai donc ajouté une étiquette au-dessus de la liste déroulante indiquant «Veuillez sélectionner». J'ai utilisé le code suivant pour l'afficher et le masquer:

  1. Lorsque j'initialise ma liste déroulante, s'il n'y a pas de valeur sélectionnée, je l'amène au premier plan et le texte est défini:

    PleaseSelectValueLabel.BringToFront();
    PleaseSelectValueLabel.Text = Constants.AssessmentValuePrompt;
    
  2. Si une valeur est sélectionnée, je l’envoie à l’arrière:

    PleaseSelectValueLabel.SendToBack();
    
  3. J'utilise ensuite les événements suivants pour déplacer l'étiquette vers le haut ou vers l'arrière, selon que l'utilisateur a sélectionné une valeur ou non:

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