locked
ComboBox et SelectedItem RRS feed

  • Question

  • Hello,

    Débutant en WinForms je suis un peu dérouté par le ctrl ComboBox (ToolStripComboBox).

    Je remplis ma Combo avec le code ci-dessous :

            /// <summary>Charge la liste des base de classements
            /// </summary>
            private void FillClassifications() {
                var dictionary = new Dictionary<int, string>();
                DBCache datas = DataManager.GetClassifications();
                foreach (DBCache.Classification row in datas.Classifications.Rows)
                {
                    dictionary.Add(row.ID, "(" + row.Code + ") " + row.Label);
                }
                // ajoute l'item par défaut
                dictionary.Add(0, "");
                ComboBox combo = ClassificationsToolStripComboBox.ComboBox;
                combo.BindingContext = this.BindingContext;
                combo.DataSource = dictionary.ToList();
                combo.DisplayMember = "Value";
                combo.ValueMember = "Key";
            }
    

    Rem : Dans Key, je mets l'ID de l'enregistrement en base de données.

    Ensuite, au moment de la fermeture du formulaire, je veux enregistrer l'item sélectionné par l'utilisateur, (donc l'ID en base de données).

    // combo des bases de classement
    int classificationID = (int)((KeyValuePair<int, string>)((ToolStripComboBox)this.ClassificationsToolStripComboBox).SelectedItem).Key;
    // int classificationID = (int)this.ClassificationsToolStripComboBox.ComboBox.SelectedValue; ne marche pas, retourne une valeur incohérente ??
    Properties.Settings.Default.MainFormClassificationID = classificationID;
    

    Le problème, c'est ensuite de restaurer l'état de la liste lors du chargement du formulaire au démarrage de l'application.

    J'imagine qu'il faut travailler avec la propriété SelectedItem .. mais je ne sais pas comment faire.
    D'autre part, j'ai essayé avec SelectedValue, mais je ne comprends pas du tout ce que retourne cette propriété.
    Ce n'est en tout cas pas la valeur de mon ID base de données, comme je l'avaius supposé

    // Si je fais ça pour sauvegarder l'état de la liste
    int classificationID = (int)this.ClassificationsToolStripComboBox.ComboBox.SelectedValue; 
    Properties.Settings.Default.MainFormClassificationID = classificationID;
    
    // puis ça pour restaurer
    this.ClassificationsToolStripComboBox.ComboBox.SelectedValue = Properties.Settings.Default.MainFormClassificationID;
    
    
    

    ça ne fonctionne pas du tout

    Merci de votre aide

    Damien
    vendredi 5 février 2010 15:07

Réponses

  • Bonjour,

    ci dessous vous trouverez un exemple avec une liste d'objet item ou via un dictionnaire ( pour être proche de votre exemple ). Il suffit de commenter l'une ou l'autre des méthodes: InitDictionnaryItem() ou InitListItem().

    .Dans les 2 cas, la sauvegarde et le restore de la valeur dans la combobox fonctionne. C'est donc peut être plutot au niveau de la lecture de vos lignes Classifications.Rows que se trouve le problème.
    Est ce que dans le dictionnaire vous avez bien une clé qui corresponde à votre ID ? Si ce n'est pas l'ID qui est renvoyé par SelectedValue, quelle est la valeur renvoyée ?

    Cordialement

    public partial class Form1 : Form
      {
        public Form1()
        {
          InitializeComponent();
    
          //this.InitListItem();
    
          this.InitDictionnaryItem();
        }
    
        public void InitDictionnaryItem()
        {
          Dictionary<int, string> dico = new Dictionary<int, string>();
          dico.Add(1, "Libelle1");
          dico.Add(2, "Libelle2");
          dico.Add(3, "Libelle3");
          dico.Add(4, "Libelle4");
    
          this.toolStripComboBox1.ComboBox.DataSource = dico.ToList();
          this.toolStripComboBox1.ComboBox.ValueMember = "Key";
          this.toolStripComboBox1.ComboBox.DisplayMember = "Value";
        }
    
        public void InitListItem()
        {
          List<Item> list = new List<Item>()
        {
          new Item(){ ID = 1, Libelle = "Libelle1"},
          new Item(){ ID = 2, Libelle = "Libelle2"},
          new Item(){ ID = 3, Libelle = "Libelle3"},
          new Item(){ ID = 4, Libelle = "Libelle4"}
        };
    
          this.toolStripComboBox1.ComboBox.DataSource = list;
          this.toolStripComboBox1.ComboBox.ValueMember = "ID";
          this.toolStripComboBox1.ComboBox.DisplayMember = "Libelle";
        }
    
        private void btnSave_Click(object sender, EventArgs e)
        {
          Properties.Settings.Default.ID = (int)this.toolStripComboBox1.ComboBox.SelectedValue;
          Properties.Settings.Default.Save();
        }
    
        private void Restore_Click(object sender, EventArgs e)
        {
          this.toolStripComboBox1.ComboBox.SelectedValue = Properties.Settings.Default.ID;
        }
      }
      public class Item
      {
        public int ID { get; set; }
        public string Libelle { get; set; }
      }
    
    • Proposé comme réponse Alex Petrescu vendredi 12 février 2010 09:56
    • Marqué comme réponse Alex Petrescu lundi 15 février 2010 13:30
    jeudi 11 février 2010 16:25
  • Bonsoir,

    effectivement en passant la propriété Sorted à true, on obtient un comportement étrange. J'ai reproduit votre problème en alimentant le dictionnaire avec :

    dico.Add(11, "D Libelle1");
    dico.Add(22, "A Libelle2");
    dico.Add(33, "B Libelle3");
    dico.Add(44, "C Libelle4");
    
    ...
    
    this.toolStripComboBox1.ComboBox.Sorted = true;

    Dans ce cas si je sélectionne la valeur "B Libelle3", SelectedValue = 22 ce qui est incorrect...et donc je suis d'accord pas du tout intuitif

    Néanmoins dans la doc Msdn il est indiqué :

    Attempting to set the Sorted property on a data-bound control raises an ArgumentException . You must sort the data using the underlying data model.

    L'erreur ne se produit que si la propriété sorted est affectée après la liaison au données, mais cela suggère de s'appuyer sur un tri directement sur le modéle.

    Par exemple pour trier la source avant le databinding :

    List<KeyValuePair<int,string>> list = dico.ToList();
    list.Sort((x, y) => string.Compare(x.Value, y.Value));
    
    this.toolStripComboBox1.ComboBox.DisplayMember = "Value";
    this.toolStripComboBox1.ComboBox.ValueMember = "Key";
    this.toolStripComboBox1.ComboBox.DataSource = list;
    

    Dans ce cas SelectedValue a bien la valeur attendue

    Cordialement
    • Marqué comme réponse Alex Petrescu lundi 15 février 2010 13:30
    vendredi 12 février 2010 18:42

Toutes les réponses


  • Bonjour,

     

    Je n’ai pas tout a fait compris la logique de votre démarche. Donc, premièrement, vous voulez prendre toutes les informations d’une table et les afficher dans une liste. Apres, vous voulez que l’utilisateur sélecte un élément de la liste et cet élément est enregistré dans la base de données pour une utilisation ultérieure. Apres, vous fermez le formulaire et l’ouvrez a nouveau. Cette fois, la liste sera remplie par l’élément sélectionné la première fois.

     

    Si cette est votre idée, vous devez avoir dans votre table un troisième colonne pour identifier les éléments sélectionnés par l’utilisateur. Et après, quand vous remplissez la liste, vous devez vérifier les éléments, si la valeur de cette colonne dit que l’élément a été sélectionné dans une session antérieure.

     

    Une clarification sur la logique de votre projet sera utile pour pouvoir mieux vous aider.

     

    Cordialement,

    Alex


    Alex Petrescu - MSFT
    mercredi 10 février 2010 10:48
  • Bonjour,

    Vous avez parfaitement compris.
    - Je charge mon formulaire
    - j'affiche tous les éléments d'une table dans une liste
    - l'utilisateur sélectionne un élement de la liste
    - .... et fait ce qu'il a à faire sur le formulaire

    Je souhaite pouvoir ouvrir ultérieurement ce formulaire avec l'élément qui avait auparavant été sélectionné par l'utilisateur... qu'il retrouve son contexte en quelque sorte.

    - .. l'utilisateur ferme le formulaire
    - .. j'enregistre dans Properties.Settings.Default.MainFormClassificationID  (fichier user.config) l'identifiant (en BDD) de l'item sélectionné dans la liste avec un appel
       à Properties.Settings.Default.Save()

    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
        <userSettings>
            <WinFormsUI.Properties.Settings>
                <setting name="MainFormClassificationID" serializeAs="String">
                    <value>2</value>
                </setting>
            </WinFormsUI.Properties.Settings>
        </userSettings>
    </configuration>
    

    - ......
    - l'utilisateur ouvre à nouveau le formulaire
    - je recharge la liste à partir de sa source, puis je sélectionne l'élément en cours lors de la fermeture du formulaire à partir de la valeur de l'ID lue dans le fichier
      user.config (disponible dans  Properties.Settings.Default.MainFormClassificationID)

    Par contre, inutile de modifier le schéma de ma table pour ça, puisque user.config/Properties.Settings fait tout le travail de sérialisation/désérialisation pour moi.

    Voilà, espérant avoir été plus clair

    Merci encore
    jeudi 11 février 2010 10:08
  • Bonjour,

    ci dessous vous trouverez un exemple avec une liste d'objet item ou via un dictionnaire ( pour être proche de votre exemple ). Il suffit de commenter l'une ou l'autre des méthodes: InitDictionnaryItem() ou InitListItem().

    .Dans les 2 cas, la sauvegarde et le restore de la valeur dans la combobox fonctionne. C'est donc peut être plutot au niveau de la lecture de vos lignes Classifications.Rows que se trouve le problème.
    Est ce que dans le dictionnaire vous avez bien une clé qui corresponde à votre ID ? Si ce n'est pas l'ID qui est renvoyé par SelectedValue, quelle est la valeur renvoyée ?

    Cordialement

    public partial class Form1 : Form
      {
        public Form1()
        {
          InitializeComponent();
    
          //this.InitListItem();
    
          this.InitDictionnaryItem();
        }
    
        public void InitDictionnaryItem()
        {
          Dictionary<int, string> dico = new Dictionary<int, string>();
          dico.Add(1, "Libelle1");
          dico.Add(2, "Libelle2");
          dico.Add(3, "Libelle3");
          dico.Add(4, "Libelle4");
    
          this.toolStripComboBox1.ComboBox.DataSource = dico.ToList();
          this.toolStripComboBox1.ComboBox.ValueMember = "Key";
          this.toolStripComboBox1.ComboBox.DisplayMember = "Value";
        }
    
        public void InitListItem()
        {
          List<Item> list = new List<Item>()
        {
          new Item(){ ID = 1, Libelle = "Libelle1"},
          new Item(){ ID = 2, Libelle = "Libelle2"},
          new Item(){ ID = 3, Libelle = "Libelle3"},
          new Item(){ ID = 4, Libelle = "Libelle4"}
        };
    
          this.toolStripComboBox1.ComboBox.DataSource = list;
          this.toolStripComboBox1.ComboBox.ValueMember = "ID";
          this.toolStripComboBox1.ComboBox.DisplayMember = "Libelle";
        }
    
        private void btnSave_Click(object sender, EventArgs e)
        {
          Properties.Settings.Default.ID = (int)this.toolStripComboBox1.ComboBox.SelectedValue;
          Properties.Settings.Default.Save();
        }
    
        private void Restore_Click(object sender, EventArgs e)
        {
          this.toolStripComboBox1.ComboBox.SelectedValue = Properties.Settings.Default.ID;
        }
      }
      public class Item
      {
        public int ID { get; set; }
        public string Libelle { get; set; }
      }
    
    • Proposé comme réponse Alex Petrescu vendredi 12 février 2010 09:56
    • Marqué comme réponse Alex Petrescu lundi 15 février 2010 13:30
    jeudi 11 février 2010 16:25
  • Bonjour, et merci pour votre réponse,

    Votre exemple fonctionne parfaitement et c'est en effet avec SelectedValue que je trouvais naturel de travailler.
    Mais comme votre question le laisse entendre, je n'ai pas dans SelectedValue une valeur exploitable..

    Voici les données de ma table et mon dictionnaire est bien en cohérence avec cette table (j'ai bien dans .Key la valeur du champ ID de la table) :

    ID Code Label Description
    1 CL1 Classement 1 Base de Classement n°1
    2 CL2 Classement 2 Base de Classement n°2
    3 AR1 Archive Base d'archive
    9 TST Test1 Base de test 1
    10 TST2 Test2 Base de test 2


    Au final, si la propriété Sorted de la comboBox est à False, j'ai bien

    ClassificationsToolStripComboBox.ComboBox.SelectedValue = ((KeyValuePair<int, string>)ClassificationsToolStripComboBox.ComboBox.SelectedItem).Key

    Si au contraire, Sorted = True, j'ai dans ClassificationsToolStripComboBox.ComboBox.SelectedValue la valeur de clef de l'élément dont le n° d'ordre d'ajout dans le dictionnaire correspond à comboBox.SelectedIndex.
    Pour être plus clair, si je sélectionne le 3ème élément dans la liste, j'obtient la clef du 3ème élément ajouté dans le dictionnaire de la source de donnée.

    Euh...ça ne fait pas ça avec votre projet... je ne comprends vraiment pas ce qui cloche.
    D'ailleurs, comment est-il possible d'avoir :

    ClassificationsToolStripComboBox.ComboBox.SelectedValue !=
               ((KeyValuePair<int, string>)ClassificationsToolStripComboBox.ComboBox.SelectedItem).Key

    Je trouve que c'est totalement contre-intuitif.. pas vous ?
    D'avance merci

    Damien

    vendredi 12 février 2010 13:58
  • Bonsoir,

    effectivement en passant la propriété Sorted à true, on obtient un comportement étrange. J'ai reproduit votre problème en alimentant le dictionnaire avec :

    dico.Add(11, "D Libelle1");
    dico.Add(22, "A Libelle2");
    dico.Add(33, "B Libelle3");
    dico.Add(44, "C Libelle4");
    
    ...
    
    this.toolStripComboBox1.ComboBox.Sorted = true;

    Dans ce cas si je sélectionne la valeur "B Libelle3", SelectedValue = 22 ce qui est incorrect...et donc je suis d'accord pas du tout intuitif

    Néanmoins dans la doc Msdn il est indiqué :

    Attempting to set the Sorted property on a data-bound control raises an ArgumentException . You must sort the data using the underlying data model.

    L'erreur ne se produit que si la propriété sorted est affectée après la liaison au données, mais cela suggère de s'appuyer sur un tri directement sur le modéle.

    Par exemple pour trier la source avant le databinding :

    List<KeyValuePair<int,string>> list = dico.ToList();
    list.Sort((x, y) => string.Compare(x.Value, y.Value));
    
    this.toolStripComboBox1.ComboBox.DisplayMember = "Value";
    this.toolStripComboBox1.ComboBox.ValueMember = "Key";
    this.toolStripComboBox1.ComboBox.DataSource = list;
    

    Dans ce cas SelectedValue a bien la valeur attendue

    Cordialement
    • Marqué comme réponse Alex Petrescu lundi 15 février 2010 13:30
    vendredi 12 février 2010 18:42