Элементы управления в WPF. Списки элементов ListBox и ComboBox

Списки элементов в WPF и, в принципе, в приложениях используются довольно часто. Такие элементы управления обычно содержат два и более однотипных объекта, которые пользователь может выбрать. В WPF существует ряд элементов управления, позволяющих хранить списки элементов и основные из них — это ListBox, ComboBoxListViewи TreeView. В этой части мы рассмотрим два из этих компонентов — ListBox и ComboBox

Списки элементов: иерархия классов

Вначале рассмотрим иерархию классов, реализующих элементы управления списками в WPF, чтобы в дальнейшем можно было систематизировать информацию по работе таких элементов:

Списки элементов ListBox и ComboBox

Элемент 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 Режим выбора элементов в списке. Может принимать следующие значения:

  • Single — можно выбрать только один элемент списка
  • Multiple — можно выбрать несколько элементов списка, не зажимая клавиши-модификаторы
  • Extended — можно выбрать несколько элементов, зажав клавишу-модификатор Shift

 

Заполнение 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());
}

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

Списки элементов ListBox и ComboBox

Использование 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>

Списки элементов ListBox и ComboBox

При этом, каждый элемент списка представляет собой 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 и ComboBox

Отображение сложных объектов в 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. В запущенном приложении наш список выбора будет работать следующим образом:

Списки элементов ListBox и 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

Итого

Списки элементов ListBox и ComboBox представляют собой элементы управления WPF, позволяющие хранить и выбирать один или несколько дочерних элементов. Для заполнения ListBox и ComboBox мы можем использовать как обычные строки, так и специальные элементы ListBoxItem и ComboBoxItem, которые позволяют размещать в элементах списка произвольные объекты и настраивать их внешний вид.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии