Класс ObservableCollection
Кроме стандартных классов коллекций типа списков, очередей, словарей, стеков .NET также предоставляет специальный класс ObservableCollection<T>. В отличие от ранее рассмотренных коллекций данный класс определен в пространстве имен System.Collections.ObjectModel. По функциональности коллекция ObservableCollection похожа на список List за тем исключением, что позволяет известить внешние объекты о том, что коллекция была изменена.
Создание и инициализация ObservableCollection
Для создания объекта класс ObservableCollection предоставляет ряд конструкторов. Прежде всего мы можем создать пустую коллекцию:
using System.Collections.ObjectModel;
ObservableCollection<string> people = new ObservableCollection<string>();
В данном случае коллекция people типизируется типом string, поэтому может хранить только строки.
Другая версия конструктора позволяет передать в ObservableCollection объекты из другой коллекции или массива:
var people = new ObservableCollection<string>( new string[] {"Tom", "Bob", "Sam"});
Для инициализации можно через инициализатор в фигурных скобках передать значения
var people = new ObservableCollection<string>
{
"Tom", "Bob", "Sam"
};
Также можно сочетать предыдущие два способа:
var people = new ObservableCollection<string>( new string[] {"Mike", "Alice", "Kate" })
{
"Tom", "Bob", "Sam"
};
Обращение к элементам коллекции
Для обращения к элементам ObservableCollection можно применять индексы на манер массивов или списков List:
var people = new ObservableCollection<string>
{
"Tom", "Bob", "Sam"
};
// получаем первый элемент
Console.WriteLine(people[0]); // Tom
// изменяем первый элемент
people[0] = "Tomas";
Console.WriteLine(people[0]); // Tomas
Перебор коллекции
Для перебора коллекции можно применять стандартные циклы:
using System.Collections.ObjectModel;
var people = new ObservableCollection<string>
{
"Tom", "Bob", "Sam"
};
foreach(var person in people)
{
Console.WriteLine(person);
}
for (int i =0; i < people.Count; i++)
{
Console.WriteLine(people[i]);
}
С помощью свойства Count можно получить количество элементов в коллекции.
Методы ObservableCollection
Среди методов класса ObservableCollection можно отметить следующие:
void Add(T item): добавление нового элемента в коллекцию
void CopyTo(T[] array, int index,): копирует в массив array элементы из коллекции начиная с индекса index
bool Contains(T item): возвращает true, если элемент item есть в коллекции
void Clear(): удаляет из коллекции все элементы
int IndexOf(T item): возвращает индекс первого вхождения элемента в коллекции
void Insert(int index, T item): вставляет элемент item в коллекцию по индексу index. Если такого индекса в коллекции нет, то генерируется исключение
bool Remove(T item): удаляет элемент item из коллекции, и если удаление прошло успешно, то возвращает true. Если в коллекции несколько одинаковых элементов, то удаляется только первый из них
void RemoveAt(int index): удаление элемента по указанному индексу index. Если такого индекса в коллекции нет, то генерируется исключение
void Move(int oldIndex, int newIndex): перемещает элемент с индекса oldIndex на позицию по индексу newIndex
Применение методов:
using System.Collections.ObjectModel;
var people = new ObservableCollection<string>();
// добавляем элемент
people.Add("Bob");
// вставляем элемент по индексу 0
people.Insert(0, "Tom");
// проверка наличия элемента
bool bobExists = people.Contains("Bob"); // true
Console.WriteLine($"Bob exists: {bobExists}");
bool mikeExists = people.Contains("Mike"); // false
Console.WriteLine($"Mike exists: {mikeExists}");
// удаляем элемент
people.Remove("Tom");
// удаляем элемент по индексу 0
people.RemoveAt(0);
Уведомление об измении коллекции
Класс ObservableCollection определяет событие CollectionChanged, подписавшись на которое, мы можем обработать любые изменения коллекции. Данное событие представляет делегат NotifyCollectionChangedEventHandler:
void NotifyCollectionChangedEventHandler(object? sender, NotifyCollectionChangedEventArgs e);
Второй параметр делегата - объект NotifyCollectionChangedEventArgs хранит всю информацию о событии. В частности, его свойство Action позволяет узнать характер изменений. Оно хранит одно из значений из перечисления NotifyCollectionChangedAction:
NotifyCollectionChangedAction.Add: добавление
NotifyCollectionChangedAction.Remove: удаление
NotifyCollectionChangedAction.Replace: замена
NotifyCollectionChangedAction.Move: перемещение объекта внутри коллекции на новую позицию
NotifyCollectionChangedAction.Reset: сброс содержимого коллекции (например, при ее очистке с помощью метода Clear())
Кроме того, свойства NewItems и OldItems позволяют получить соответственно добавленные и удаленные объекты. Таким образом, мы получаем полный контроль над обработкой добавления, удаления и замены объектов в коллекции.
Допустим, у нас будет следующий класс Person, который представляет пользователя:
class Person
{
public string Name { get; }
public Person(string name) => Name = name;
}
Для управления коллекцией объектов Person определим следующую программу:
using System.Collections.ObjectModel;
using System.Collections.Specialized;
var people = new ObservableCollection<Person>()
{
new Person("Tom"),
new Person("Sam")
};
// подписываемся на событие изменения коллекции
people.CollectionChanged += People_CollectionChanged;
people.Add(new Person("Bob")); // добавляем новый элемент
people.RemoveAt(1); // удаляем элемент
people[0] = new Person("Eugene"); // заменяем элемент
Console.WriteLine("\nСписок пользователей:");
foreach (var person in people)
{
Console.WriteLine(person.Name);
}
// обработчик изменения коллекции
void People_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add: // если добавление
if(e.NewItems?[0] is Person newPerson)
Console.WriteLine($"Добавлен новый объект: {newPerson.Name}");
break;
case NotifyCollectionChangedAction.Remove: // если удаление
if (e.OldItems?[0] is Person oldPerson)
Console.WriteLine($"Удален объект: {oldPerson.Name}");
break;
case NotifyCollectionChangedAction.Replace: // если замена
if ((e.NewItems?[0] is Person replacingPerson) &&
(e.OldItems?[0] is Person replacedPerson))
Console.WriteLine($"Объект {replacedPerson.Name} заменен объектом {replacingPerson.Name}");
break;
}
}
Здесь в качестве обработчика изменений коллекции выступает метод People_CollectionChanged, в котором с помощью параметра NotifyCollectionChangedEventArgs получаем информацию об изменении. Консольный вывод программы:
Добавлен новый объект: Bob
Удален объект: Sam
Объект Tom заменен объектом Eugene
Список пользователей:
Eugene
Bob