Работа с коллекциями данных. ObservableCollection

Последнее обновление: 26.02.2016

В прошлых темах были рассмотрены примеры привязки отдельных объектов к элементам интерфейса. Но, как правило, приложения оперируют не одиночными данными, а большими наборами, коллекциями объектов. Для работы непосредственно с наборами данных в WPF определены различные элементы управления списками, такие как ListBox, ListView, DataGrid, TreeView, ComboBox.

Их отличительной особенностью является то, что они наследуются от базового класса ItemsControl и поэтому наследуют ряд общей функциональности для работы с данными. Прежде всего можно выделить свойства:

  • Items: устанавливает набор объектов внутри элемента

  • ItemsSource: ссылка на источник данных

  • ItemStringFormat: формат, который будет использоваться для форматирования строк, например, при переводе в строку числовых значений

  • ItemContainerStyle: стиль, который устанавливается для контейнера каждого элемента (например, для ListBoxItem или ComboBoxItem)

  • ItemTemplate: представляет шаблон данных, который используется для отображения элементов

  • ItemsPanel: панель, которая используется для отображения данных. Как правило, применяется VirtualizingStackPanel

  • DisplayMemberPath: свойство, которое будет использоваться для отображения в списке каждого объекта

При работе с элементами управления списками важно понимать, что эти элементы предназначены прежде всего для отображения данных, а не для хранения. В каких-то ситуациях мы, конечно, можем определять небольшие списки непосредственно внутри элемента. Например:

<ListBox>
    <ListBox.Items>
        <ListBoxItem>iPhone 6S Plus</ListBoxItem>
        <ListBoxItem>Nexus 6P</ListBoxItem>
        <ListBoxItem>Galaxy S7 Edge</ListBoxItem>
    </ListBox.Items>
</ListBox>

Но в большинстве случае предпочтительнее использовать привязку к спискам и разделять источник данных от их представления или визуализации. Например, определим ListBox:

<ListBox x:Name="phonesList" />

А в коде c# создадим источник данных и установим привязку к нему:

public partial class MainWindow : Window
{
    List<string> phones;
    public MainWindow()
    {
        InitializeComponent();

        phones = new List<string> {"iPhone 6S Plus", "Nexus 6P", "Galaxy S7 Edge" };
        phonesList.ItemsSource = phones;
    }
}

ObservableCollection

В примере выше в качестве источника данных использовался список List. Также в качестве источника мы бы могли использовать другой какой-нибудь тип набора данных - массив, объект HashSet и т.д. Но нередко в качестве источника применяется класс ObservableCollection, который находится в пространстве имен System.Collections.ObjectModel. Его преимущество заключается в том, что при любом изменении ObservableCollection может уведомлять элементы, которые применяют привязку, в результате чего обновляется не только сам объект ObservableCollection, но и привязанные к нему элементы интерфейса.

Например, рассмотрим следующую ситуацию. У нас кроме элемента ListBox есть текстовое поле и кнопка для добавления нового объекта:

<Window x:Class="DataApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DataApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="250" Width="300" Name="mainWindow">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <ListBox x:Name="phonesList" />
        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0 15 0 0" HorizontalAlignment="Center">
            <TextBox Name="phoneTextBox" Width="190" />
            <Button Content="Сохранить" MaxWidth="70" Margin="10 0 0 0" Click="Button_Click" />
        </StackPanel>
    </Grid>
</Window>

В файле кода определим обработчик кнопки, в котором новый элемент добавлялся бы в источник данных:

public partial class MainWindow : Window
{
    List<string> phones;
    public MainWindow()
    {
        InitializeComponent();

        phones = new List<string> {"iPhone 6S Plus", "Nexus 6P", "Galaxy S7 Edge" };
        phonesList.ItemsSource = phones;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string phone = phoneTextBox.Text;
		// добавление нового объекта
        phones.Add(phone);
    }
}

По нажатию на кнопку должно произойти добавления в список phones введенной в текстовое поле строки. И мы ожидаем, что после добавления ListBox отобразит нам добавленный объект. Однако так как в качестве источника применяется List, то обновления элемента ListBox не произойдет. Поэтому заменим List на ObservableCollection:

public partial class MainWindow : Window
{
    ObservableCollection<string> phones;
    public MainWindow()
    {
        InitializeComponent();

        phones = new ObservableCollection<string> {"iPhone 6S Plus", "Nexus 6P", "Galaxy S7 Edge" };
        phonesList.ItemsSource = phones;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string phone = phoneTextBox.Text;
		// добавление нового объекта
        phones.Add(phone);
    }
}

И теперь у нас уже не возникнет подобной проблемы:

ObservableCollection в WPF
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850