c# - Liaison de données WinForms ComboBox gotcha

Translate

Supposons que vous faites quelque chose comme ce qui suit

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

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

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

Nous avons donc maintenant 2 combos liés à ce tableau, et tout fonctionne bien. Mais lorsque vous modifiez la valeur d'une zone de liste déroulante, les DEUX zones de liste déroulante sont remplacées par celle que vous venez de sélectionner.

Maintenant, je sais que les tableaux sont toujours passés par référence (appris cela quand j'ai appris C: D), mais pourquoi diable les combos changeraient-ils ensemble? Je ne pense pas que le contrôle de la zone de liste modifie du tout la collection.

Comme solution de contournement, cela n'atteindrait pas la fonctionnalité attendue / souhaitée

ComboBox box = new ComboBox();
box.DataSource = myitems.ToArray();
This question and all comments follow the "Attribution Required."

Toutes les réponses

Translate

Cela a à voir avec la façon dont les liaisons de données sont configurées dans le framework dotnet, en particulier leContexte de liaison. À 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êmeBindingContext. Lorsque vous réglez leDataSourcepropriété leComboBoxutilisera leBindingContextpour obtenir unConcurrenyMangagerqui enveloppe la liste. leConcurrenyManagergarde une trace de choses telles que la position actuelle sélectionnée dans la liste.

Lorsque vous définissez leDataSourcedu secondComboBoxil utilisera le mêmeBindingContext(les formes) qui donneront une référence au mêmeConcurrencyManagercomme ci-dessus, utilisé pour configurer les liaisons de données.

Pour obtenir une explication plus détaillée, voirBindingContext.

La source
Translate

Une meilleure solution de contournement (en fonction de la taille de la source de données) consiste à déclarer deuxBindingSourceles objets (nouveaux à partir de 2.00) lient la collection à ceux-ci, puis les lient 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<string> myitems = new List<string>
            {
                "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 embrouiller encore plus, essayez de toujours déclarer des liaisons dans le constructeur. Cela peut entraînervraimentbugs curieux, donc je lie toujours dans l'événement Load.

La source