Как я могу привязать данные к свойствам, не связанным с элементом списка в классах, производных List <T> - PullRequest
3 голосов
/ 09 ноября 2008

Раньше у меня был класс, который обернул внутренний System.Collections.Generic.List<Item> (где Item - это класс, который я создал). Класс-оболочка предоставил несколько свойств уровня коллекции, которые предоставили итоги, средние значения и другие вычисления для элементов в списке. Я создавал BindingSource вокруг этого обернутого List<> и еще одного BindingSource вокруг моего класса и смог получить доступ к элементам в обернутом списке через первый BindingSource и свойства уровня коллекции класса обертки, используя второй.

Упрощенный пример выглядит так:

public class OldClass()
{
  private List<Item> _Items;

  public OldClass()
  {
    _Items = new List<Item>();
  }

  public List<Item> Items { get { return _Items; } }

  // collection-level properties
  public float AverageValue { get { return Average() } }
  public float TotalValue { get { return Total() } }
  // ... other properties like this

}

С источниками привязки, созданными таким образом:

_itemsBindingSource = new BindingSource(oldClass.Items);
_summaryBindingSource = new BindingSource(oldClass);

Недавно я попытался изменить этот класс, чтобы он был производным от System.Collections.Generic.List<Item> вместо того, чтобы хранить завернутый List<> член. Я надеялся избавиться от лишнего слоя-обертки и использовать только один BindingSource вместо двух. Однако теперь я обнаружил, что не могу получить свойства, которые применяются ко всем элементам в списке (например, AverageValue), когда я выполняю привязку данных. Доступны только свойства элементов списка.

Я вынужден вернуться к использованию обернутых List<> из Item с? Или есть способ, которым я могу получить как свойства Item s, хранящиеся в моем новом классе, так и свойства, которые применяются к самой коллекции?

Ответы [ 3 ]

5 голосов
/ 09 ноября 2008

Система обрабатывает все, что реализует IList (или IListSource), как контейнер, а не как элемент. Таким образом, вы не можете связать со свойствами чего-либо, что реализует IList. Таким образом, инкапсуляция (то есть то, что у вас уже есть) является наилучшим подходом, если вы хотите иметь возможность привязки к свойствам контейнера.

Однако вы должны заметить, что многие привязки поддерживают точечную нотацию в источнике - то есть либо привязка к "Items.SomeProperty", либо установка вспомогательного свойства (обычно DataMember) для указания подсписков.

Это позволяет вам иметь один BindingSource и иметь разные элементы управления, привязанные к разным уровням в иерархии - т.е. вы можете иметь TextBox, привязанный к AverageValue, и DataGridView (с тем же DataSource) с DataMember="Items".

0 голосов
/ 09 ноября 2008

Вместо создания класса-оболочки вокруг вашего List, вы рассматривали возможность создания класса расширения (при условии, что вы используете C # 3)

public static class MyExtensions
{
    public static float GetAverage(this List<Item>)
    {
        // implementation
    }

    public static float GetTotal(this List<Item>)
    {
        // implementation
    }
}

Конечно, ваши свойства становятся вызовами методов ( возможно C # 4 исправит это ), но вы полностью удалите оболочку.

0 голосов
/ 09 ноября 2008

Проблема в том, что вы хотите использовать один класс для двух совершенно разных целей (с точки зрения привязок).

Пример. Свойство AverageValue не имеет смысла указывать для каждого элемента, поскольку это глобальное свойство, охватывающее все элементы.

В любом случае, я предполагаю, что ваш _itemsBindingSource предназначен для ComboBox или чего-то еще, а ваш _summaryBindingSource предназначен для PropertyGrid (или чего-то в этом роде).

То, что вы могли бы сделать, чтобы могло работать в вашей ситуации (я не могу быть уверен, потому что я не знаю, что вы на самом деле делаете), это:

1) Заставьте ваш "OldClass" реализовать IEnumerable ... и в этом просто вернуть перечисление из списка. Это даст вам возможность связываться со «oldClass» вместо «oldClass.Items».

2) Создайте поле "Public List Items" вместо свойства ... или добавьте атрибут "Browsable (false)", чтобы он не привязывался к PropertyGrid (это предположение, поскольку неясно для чего вы используете эти привязки).

...