WinForms ComboBox liaison de données gotcha

Supposons que vous faites quelque chose comme le suivant

List myitems = new List
{
    "Item 1",
    "Item 2",
    "Item 3"
};

ComboBox box = new ComboBox();
box.DataSource = myitems;

ComboBox box2 = new ComboBox();
box2.DataSource = myitems

Alors maintenant, nous avons 2 boîtes de liste déroulantes liées à ce tableau, et tout fonctionne bien. Mais lorsque vous modifiez la valeur d'une zone de liste déroulante, elle modifie les deux zones de liste déroulante à celle que vous venez de sélectionner.

Maintenant, je sais que les tableaux sont toujours passés par référence (appris que quand j'ai appris C: D), mais pourquoi les boîtes de combo changeraient-elles ensemble? Je ne crois pas que le contrôle de la combo modifie la collection du tout.

Comme un travail autour, ne serait-ce pas atteindre la fonctionnalité qui est attendue / désirée

ComboBox box = new ComboBox();
box.DataSource = myitems.ToArray();
0
ajouté édité
Vues: 2

3 Réponses

Cela a à voir avec la manière dont les liaisons de données sont configurées dans le framework dotnet, en particulier le BindingContext . À un niveau élevé, cela signifie que si vous n'avez pas spécifié autrement, chaque formulaire et tous les contrôles du formulaire partagent le même BindingContext . Lorsque vous définissez la propriété DataSource , ComboBox utilisera le BindingContext pour obtenir un ConcurrenyMangager qui enveloppe la liste. Le ConcurrenyManager conserve la trace de la position sélectionnée dans la liste.

Lorsque vous définissez DataSource du second ComboBox , il utilisera le même BindingContext (les formulaires) qui donnera une référence au même ConcurrencyManager comme ci-dessus utilisé pour configurer les liaisons de données.

Pour obtenir une explication plus détaillée, consultez BindingContext .

0
ajouté
On dirait que beaucoup d'efforts ne fournissent aucun avantage et rendent les contrôles de liaison de données complètement contre-intuitifs.
ajouté l'auteur Belmiris, source

Une meilleure solution (en fonction de la taille de la source de données) consiste à déclarer deux objets BindingSource (nouveau à partir de 2.00) en liant la collection à ceux-ci, puis en les associant aux comboboxes.

Je joins un exemple complet.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication2
{
    public partial class Form1 : Form
    {
        private BindingSource source1 = new BindingSource();
        private BindingSource source2 = new BindingSource();

        public Form1()
        {
            InitializeComponent();
            Load += new EventHandler(Form1Load);
        }

        void Form1Load(object sender, EventArgs e)
        {
            List myitems = new List
            {
                "Item 1",
                "Item 2",
                "Item 3"
            };

            ComboBox box = new ComboBox();
            box.Bounds = new Rectangle(10, 10, 100, 50);
            source1.DataSource = myitems;
            box.DataSource = source1;

            ComboBox box2 = new ComboBox();
            box2.Bounds = new Rectangle(10, 80, 100, 50);
            source2.DataSource = myitems;
            box2.DataSource = source2;

            Controls.Add(box);
            Controls.Add(box2);
        }
    }
}

Si vous voulez vous confondre encore plus, essayez toujours de déclarer les liaisons dans le constructeur. Cela peut entraîner des bugs curieux vraiment , donc je lie toujours dans l'évènement Load.

0
ajouté
J'ai trouvé certains des bogues les plus bizarres non signalés avec cela. Dans le pire des cas, une combobox a refusé de se concentrer sur un autre contrôle: D
ajouté l'auteur Quibblesome, source
Merci d'indiquer que la liaison dans le constructeur se traduit par des bogues très curieux. J'ai eu un problème similaire et je me suis déplacé mon code pour l'événement Load et il a montré les données liées.
ajouté l'auteur bunggo, source

Cela pourrait être juste une faute de frappe, mais dans le code que vous avez fourni, vous ne faites référence qu'à la première zone de liste déroulante lors de la définition de la source de données:

ComboBox box = new ComboBox();
box.DataSource = myitems;

ComboBox box2 = new ComboBox();
**box**.DataSource = myitems

La source de données pour box2 n'est pas définie.

0
ajouté