Содержание
Списки элементов в WPF и, в принципе, в приложениях используются довольно часто. Такие элементы управления обычно содержат два и более однотипных объекта, которые пользователь может выбрать. В WPF существует ряд элементов управления, позволяющих хранить списки элементов и основные из них — это ListBox, ComboBox, ListViewи TreeView. В этой части мы рассмотрим два из этих компонентов — ListBox и ComboBox
Списки элементов: иерархия классов
Вначале рассмотрим иерархию классов, реализующих элементы управления списками в WPF, чтобы в дальнейшем можно было систематизировать информацию по работе таких элементов:
Элемент ItemsControl
Все элементы управления списками в WPF имею одного общего предка — класс ItemsControl, который представляет собой элемент управления для хранения и работы со коллекциями других элементов. В частности, этот класс предоставляет нам следующие свойства для работы с коллекциями элементов:
| Свойство | Тип | Описание |
Items |
ItemCollection |
Коллекция, используемая для создания содержимого ItemsControl (только для чтения) |
ItemsSource |
IEnumerable |
Коллекция, используемая для создания содержимого ItemsControl (свойство доступно для чтения и записи) |
В свою очередь, свойство ItemCollection предоставляет нам следующие методы для управления коллекцией элементов:
| Метод | Описание |
public int Add(object newItem); |
Добавляет новый элемент в список и возвращает индекс добавленного элемента в коллекции |
public void Clear(); |
Удаляет все элементы из коллекции |
public override bool Contains(object containItem); |
Проверяет наличие элемента containItem в коллекции |
public void Insert(int insertIndex, object insertItem); |
Вставляет элемент insertItem в позицию insertIndex |
public void Remove(object removeItem); |
Удаляет элемент removeItem из коллекции |
public void RemoveAt(int removeIndex); |
Удаляет из коллекции элемент с индексом removeIndex |
Компонент Selector
Класс Selector наследуется от ItemsControl и предоставляет элемент управления, позволяющий пользователю выбрать один из его дочерних элементов. Этот класс дополняет работу со списками элементов следующими свойствами:
| Свойство | Тип | Описание |
SelectedIndex |
int |
Индекс выбранного пользователем элемента в списке |
SelectedItem |
object |
Выбранный пользователем элемент |
SelectedValue |
object |
Значение SelectedItem, получаемое через SelectedValuePath. |
SelectedValuePath |
string |
Путь для получения SelectedItem или SelectedValue |
Также, этот элемент предоставляет нам событие:
| Событие | Описание |
public event SelectionChangedEventHandler SelectionChanged; |
Генерируется при изменении выбора элемента в списке |
Таким образом, элементы управления ListBox и ComboBox в WPF получаю все свойства и события своих предком — классов ItemsControl и Selector, позволяя манипулировать списком элементов. Теперь рассмотрим непосредственно эти элементы управления.
Списки элементов: ListBox
Элемент управления ListBox представляет собой простой список выбора, при этом, пользователь может выбрать как один, так и несколько элементов. Класс ListBox предоставляет нам для работы следующие свойства:
| Свойство | Тип | Описание |
SelectedItems |
IList |
Список выбранных элементов |
SelectionMode |
SelectionMode |
Режим выбора элементов в списке. Может принимать следующие значения:
|
Заполнение ListBox в WPF строками
Рассмотрим работу с ListBox на следующем примере:
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Grid>
<ListBox x:Name="list" SelectionMode="Single" SelectionChanged="ListBox_SelectionChanged">
<sys:String>Первый</sys:String>
<sys:String>Второй</sys:String>
<sys:String>Третий</sys:String>
<sys:String>Четвертый</sys:String>
</ListBox>
</Grid>
</Window>
В качестве элементов ListBox мы используем обычные строки, для чего подключаем пространство имен:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Режим выбора элементов мы устанавливаем как Single, чтобы можно было за раз выбрать только один элемент списка и определяем обработчик события SelectionChanged, который выглядит следующим образом:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (list.SelectedItem != null)
MessageBox.Show(list.SelectedItem.ToString());
}
Запустим приложение и попробуем выбрать какой-нибудь элемент списка:
Использование ListBoxItem в WPF для заполнения ListBox
Ещё один вариант формирования списка ListBox непосредственно в разметке XAML заключается в использовании специального элемента ListBoxItem, например, так:
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ListBox x:Name="list" SelectionMode="Extended" SelectionChanged="ListBox_SelectionChanged">
<ListBoxItem>Первый</ListBoxItem>
<ListBoxItem>Второй</ListBoxItem>
<ListBoxItem>Третий</ListBoxItem>
<ListBoxItem>Четвертый</ListBoxItem>
</ListBox>
</Grid>
</Window>
Этот способ избавляет нас от необходимости подключения дополнительного пространства имен, а также расширяет возможности работы с элементами списка, например, задать свойства фона, цвета текста элемента или сразу установить выбранный элемент списка:
<ListBox x:Name="list" SelectionMode="Extended" SelectionChanged="ListBox_SelectionChanged">
<ListBoxItem Background="LightGreen" IsSelected="True">Первый</ListBoxItem>
<ListBoxItem Background="LightBlue" Foreground="Blue">Второй</ListBoxItem>
<ListBoxItem Background="LightPink" Foreground="Red">Третий</ListBoxItem>
<ListBoxItem>Четвертый</ListBoxItem>
</ListBox>
При этом, каждый элемент списка представляет собой ListBoxItem, то есть, для доступа к содержимому элемента мы должны немного переписать обработчик события SelectionChanged следующим образом:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (list.SelectedItem != null)
{
if ((list.SelectedItem is ListBoxItem data) && (data.Content != null))
MessageBox.Show(data.Content.ToString());
}
}
Теперь при запуске приложения будет сразу выбран первый элемент списка.
Программное заполнение ListBox в WPF
Для заполнения списка элементов ListBox мы можем воспользоваться свойством Items. Изменим разметку XAML следующим образом:
<Window x:Class="WpfApp3.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:WpfApp3"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<ListBox x:Name="list" SelectionMode="Extended" SelectionChanged="ListBox_SelectionChanged">
<ListBoxItem Background="LightGreen">Смартфоны</ListBoxItem>
<ListBoxItem Background="LightBlue" Foreground="Blue">Программное обеспечение</ListBoxItem>
<ListBoxItem Background="LightPink" Foreground="Red">Языки программирования</ListBoxItem>
</ListBox>
<ListBox x:Name="elements"></ListBox>
</StackPanel>
</Window>
Здесь мы добавили новый список ListBox с именем elements:
<ListBox x:Name="elements"></ListBox>
Теперь перепишем обработчик SelectionChanged первого списка следующим образом:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (list.SelectedItem != null)
{
if ((list.SelectedItem is ListBoxItem data) && (data.Content != null))
{
elements.Items.Clear();
switch (data.Content.ToString())
{
case "Смартфоны":
{
elements.Items.Add("iPhone");
elements.Items.Add("Xiomi");
elements.Items.Add("Samsung");
break;
}
case "Программное обеспечение":
{
elements.Items.Add("Visual Studio");
elements.Items.Add("Microsoft Windows");
elements.Items.Add("Microsoft Office");
break;
}
case "Языки программирования":
{
elements.Items.Add("C#");
elements.Items.Add("Basic");
elements.Items.Add("Python");
break;
}
}
}
}
}
При выборе элемента в первом списке все элементы во втором списке удаляются:
elements.Items.Clear();
а, затем, в зависимости от выбранного значения, заполняется новыми элементами. Вот как будет выглядеть результат работы приложения:
Отображение сложных объектов в ListBox
Часто нам необходимо отобразить в списке ListBox данные какого-либо сложного объекта, например, рассмотрим заполнение ListBox объектами следующего типа:
public class Element
{
public int Id { get; set; }
public string? Name { get; set; }
}
Для того, чтобы заполнить ListBox такими элементами, нам необходимо воспользоваться свойством ItemSource. Например, перепишем работу с нашими списками следующим образом:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (list.SelectedItem != null)
{
if ((list.SelectedItem is ListBoxItem data) && (data.Content != null))
{
switch (data.Content.ToString())
{
case "Смартфоны":
{
elements.ItemsSource = new List<Element>()
{
new Element(){ Id=1, Name = "iPhone"},
new Element(){ Id=2, Name = "Xiomi"},
new Element(){ Id=3, Name = "Samsung"},
};
break;
}
case "Программное обеспечение":
{
elements.ItemsSource = new List<Element>()
{
new Element(){ Id=1, Name = "Visual Studio"},
new Element(){ Id=2, Name = "Microsoft Windows"},
new Element(){ Id=3, Name = "Microsoft Office"},
};
break;
}
case "Языки программирования":
{
elements.ItemsSource = new List<Element>()
{
new Element(){ Id=1, Name = "C#"},
new Element(){ Id=2, Name = "Basic"},
new Element(){ Id=3, Name = "Python"},
};
break;
}
}
elements.DisplayMemberPath = "Name";
}
}
}
Обратите внимание, что при использовании свойства ItemSource нам становится недоступно свойство Items. Свойству ItemSource мы сразу назначаем список элементов:
elements.ItemsSource = new List<Element>()
{
new Element(){ Id=1, Name = "iPhone"},
new Element(){ Id=2, Name = "Xiomi"},
new Element(){ Id=3, Name = "Samsung"},
};
Для того, чтобы указать значение какого свойства объекта необходимо отображать в списке, мы указываем значение свойства DisplayMemberPath :
elements.DisplayMemberPath = "Name";
Таким образом, в свойстве SelectedItem теперь будет содержаться объект типа Element, а отображаться в списке будет значение свойства Name.
Списки элементов: ComboBox
Элемент управления ComboBox представляет собой раскрывающийся список элементов. Способы создания таких списков аналогичны способам рассмотренным выше для ListBox, поэтому не будем повторяться, а сразу рассмотрим свойства ComboBox и немного поэкспериментируем с его оформлением. Итак, ComboBox предоставляет нам следующие свойства:
| Свойство | Тип | Описание |
IsDropDownOpen |
bool |
Указывает раскрыт ли список выбора в данный момент |
IsEditable |
bool |
Указывает доступно ли редактирование текста в поле ComboBox |
IsReadOnly |
bool |
Определяет доступ только для чтения |
StaysOpenOnEdit |
bool |
Определяет будет ли раскрыт список выбора, когда пользователь щелкает по текстовому полю ComboBox |
Text |
string |
Текст в поле ComboBox |
Создадим следующий элемент управления ComboBox:
<ComboBox StaysOpenOnEdit="True" IsEditable="True" IsReadOnly="False">
<ComboBoxItem>Телефоны</ComboBoxItem>
<ComboBoxItem>Ноутбуки</ComboBoxItem>
<ComboBoxItem>Бытовая техника</ComboBoxItem>
</ComboBox>
Здесь мы для заполнения списка воспользовались элементами ComboBoxItem и допускаем возможность ручного ввода значений в поле ComboBox. В запущенном приложении наш список выбора будет работать следующим образом:
Так как ComboBoxItem может иметь любое содержимое, то ничто нам не мешает расположить в нем и другие элементы управления WPF, например:
<StackPanel>
<ComboBox StaysOpenOnEdit="True" IsEditable="False" IsReadOnly="True">
<ComboBoxItem>
<StackPanel>
<TextBlock FontSize="16" FontWeight="Bold">Телефоны</TextBlock>
<TextBlock FontSize="10" Foreground="Gray">Список моделей телефонов</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel>
<TextBlock FontSize="16" FontWeight="Bold">Ноутбуки</TextBlock>
<TextBlock FontSize="10" Foreground="Gray">Список моделей ноутбуков</TextBlock>
</StackPanel>
</ComboBoxItem>
<ComboBoxItem>
<StackPanel>
<TextBlock FontSize="16" FontWeight="Bold">Бытовая техника</TextBlock>
<TextBlock FontSize="10" Foreground="Gray">Телевизоры, холодильники, стиральные машины</TextBlock>
</StackPanel>
</ComboBoxItem>
</ComboBox>
</StackPanel>
Теперь наш список выбора будет выглядеть следующим образом:
Итого
Списки элементов ListBox и ComboBox представляют собой элементы управления WPF, позволяющие хранить и выбирать один или несколько дочерних элементов. Для заполнения ListBox и ComboBox мы можем использовать как обычные строки, так и специальные элементы ListBoxItem и ComboBoxItem, которые позволяют размещать в элементах списка произвольные объекты и настраивать их внешний вид.





