Проекционный класс bindinglist фантик
Есть ли простой способ создать оболочку BindingList
(с проекцией), которая будет обновляться по мере обновления исходного списка?
BindingList<int> numbers = data.GetNumbers();
comboBox.DataSource = Project(numbers, i => string.Format("{0:x}", i));
Я мог бы обернуть список в Новый BindingList
, обработать все исходные события, обновить список и снова запустить эти события, но я чувствую, что уже есть более простой способ.1 ответ:
Я только что наткнулся на этот вопрос, и я понял, что могу опубликовать код, с которым я закончил.
Так как я хотел быстрого решения, я сделал своего рода реализацию бедного человека. Он работает как оболочка вокруг существующего исходного списка, но создает полный проецируемый список элементов и обновляет его по мере необходимости. Сначала я надеялся, что смогу сделать проекцию на лету, поскольку элементы доступны, но для этого потребуется реализовать весь интерфейсIBindingList
с нуля.Что is does: любые обновления исходного списка также обновят целевой список, поэтому связанные элементы управления будут должным образом обновлены.
Что он не делает: он не обновляет исходный список при изменении целевого списка. Для этого потребовалась бы функция инвертированной проекции, а мне эта функция все равно не нужна. Таким образом, элементы всегда должны быть добавлены, изменены или удалены в списке источников.
Ниже приведен пример использования . допустим, у нас есть список номеров, но мы хотим, чтобы отображение их квадратных значений в таблице данных:
// simple list of numbers List<int> numbers = new List<int>(new[] { 1, 2, 3, 4, 5 }); // wrap it in a binding list BindingList<int> sourceList = new BindingList<int>(numbers); // project each item to a squared item BindingList<int> squaredList = new ProjectedBindingList<int, int> (sourceList, i => i*i); // whenever the source list is changed, target list will change sourceList.Add(6); Debug.Assert(squaredList[5] == 36);
И вот исходный код:
Я надеюсь, что кто-то найдет это полезным.public class ProjectedBindingList<Tsrc, Tdest> : BindingList<Tdest> { private readonly BindingList<Tsrc> _src; private readonly Func<Tsrc, Tdest> _projection; public ProjectedBindingList( BindingList<Tsrc> source, Func<Tsrc, Tdest> projection) { _projection = projection; _src = source; RecreateList(); _src.ListChanged += new ListChangedEventHandler(_src_ListChanged); } private void RecreateList() { RaiseListChangedEvents = false; Clear(); foreach (Tsrc item in _src) this.Add(_projection(item)); RaiseListChangedEvents = true; } void _src_ListChanged(object sender, ListChangedEventArgs e) { switch (e.ListChangedType) { case ListChangedType.ItemAdded: this.InsertItem(e.NewIndex, Proj(e.NewIndex)); break; case ListChangedType.ItemChanged: this.Items[e.NewIndex] = Proj(e.NewIndex); break; case ListChangedType.ItemDeleted: this.RemoveAt(e.NewIndex); break; case ListChangedType.ItemMoved: Tdest movedItem = this[e.OldIndex]; this.RemoveAt(e.OldIndex); this.InsertItem(e.NewIndex, movedItem); break; case ListChangedType.Reset: // regenerate list RecreateList(); OnListChanged(e); break; default: OnListChanged(e); break; } } Tdest Proj(int index) { return _projection(_src[index]); } }