Ошибка привязки данных WinForms ComboBox
-
08-06-2019 - |
Вопрос
Предположим, вы делаете что-то вроде следующего
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
Итак, теперь у нас есть два поля со списком, привязанные к этому массиву, и все работает нормально.Но когда вы меняете значение одного поля со списком, ОБА поля со списком заменяются на то, которое вы только что выбрали.
Теперь я знаю, что массивы всегда передаются по ссылке (узнал это, когда выучил C: D), но с какой стати поля со списком должны меняться вместе?Я не верю, что элемент управления «поле со списком» вообще изменяет коллекцию.
В качестве обходного пути это не приведет к достижению ожидаемой/желаемой функциональности.
ComboBox box = new ComboBox();
box.DataSource = myitems.ToArray();
Решение
Это связано с тем, как привязки данных настраиваются в платформе dotnet, особенно BindingContext
.На высоком уровне это означает, что, если вы не указали иное, каждая форма и все элементы управления формы имеют одинаковую структуру. BindingContext
.Когда вы устанавливаете DataSource
собственность ComboBox
будет использовать BindingContext
чтобы получить ConcurrenyMangager
это завершает список.А ConcurrenyManager
отслеживает такие вещи, как текущая выбранная позиция в списке.
Когда вы установите DataSource
второго ComboBox
он будет использовать то же самое BindingContext
(формы), которые дадут ссылку на один и тот же ConcurrencyManager
как указано выше, используется для настройки привязок данных.
Чтобы получить более подробное объяснение, см. Контекст привязки.
Другие советы
Лучшим обходным решением (в зависимости от размера источника данных) является объявление двух BindingSource
объекты (новые с версии 2.00) привязывают к ним коллекцию, а затем привязывают их к полям со списком.
Прилагаю полный пример.
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);
}
}
}
Если вы хотите запутать себя еще больше, попробуйте всегда объявлять привязки в конструкторе.Это может привести к некоторым Действительно любопытные ошибки, поэтому я всегда привязываю событие Load.