Вы зашли как: Гость
Опрос
Верите ли вы в скорый выход Surface Andromeda?
31.05.2018 16:01 | dronov_va

Третья, последняя, часть статьи, посвящённой использованию простых списков в универсальных приложениях Windows 10.


1.5. Настройка представления пунктов раскрывающегося списка с помощью стилей

Ещё мы можем задать представление для самих объектов класса ComboBoxItem, представляющих пункты списка. Для этого применяются стили UWP.


1.5.1. Задание одного стиля для всех пунктов списка

Опять же, чаще всего задают один стиль, действующий на все пункты списка. Делается это посредством свойства ItemContainerStyle, унаследованного классом ComboBox от его родителя ItemsControl. Стиль, заносимый в это свойство, представляется, как обычно, объектом класса Style.

При создании стиля не забываем указать целевой класс элементов интерфейса, к которому он будет применён. В случае раскрывающегося списка это будет класс ComboBoxItem. Целевой класс задаётся в свойстве TargetType класса Style.

Экспериментировать с заданием стиля для пунктов списка мы будем на одном из наших старых проектов, например, ComboBox2. Откроем его и сразу же переключимся на интерфейсный код начальной страницы. Найдём тег <ComboBox>, создающий любой из имеющихся там списков, и добавим в него фрагмент, определяющий стиль:

<ComboBox . . .>
. . .
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="FontFamily" Value="Courier"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Black"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>


Здесь мы задали для пунктов списка шрифт Courier размером 20 пикселов, белый цвет текста и чёрный цвет фона.

Если мы запустим приложение на выполнение, сразу же увидим результат задания стиля (рис. 7).


Рис. 7. Окно исправленного приложения ComboBox2. Для пунктов списка задан стиль




1.5.2. Задание разных стилей для разных пунктов списка

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

Сначала объявляется класс, который будет проверять условие для очередного пункта списка и на основании результатов проверки назначать для этого пункта тот или иной стиль. Такой класс должен быть потомком класса StyleSelector из пространства имён Windows.UI.Xaml.Controls. В этом классе нужно переопределить метод SelectStyleCore:

protected virtual Style SelectStyleCore(Object <Объект-пункт>, DependencyObject <Контейнер пункта>)

Как видно, этот метод принимает в качестве параметров объект, формирующий пункт, и объект контейнера, в котором находится этот пункт, и возвращает нужный стиль.

После всего этого остаётся только присвоить объект такого класса свойству ItemContainerStyleSelector списка.

Откроем проект ComboBox4. Добавим в него новый файл программного кода MySS.cs, в котором объявим класс MySS, выбирающий стиль в зависимости от значения свойства simple класса PL. Вот код обяъвления этого класса:

public class MySS: Windows.UI.Xaml.Controls.StyleSelector
{
public Windows.UI.Xaml.Style SimpleStyle { get; set; }
public Windows.UI.Xaml.Style ComplexStyle { get; set; }

protected override Windows.UI.Xaml.Style SelectStyleCore(Object item,
Windows.UI.Xaml.DependencyObject container)
{
var list = item as PL;
if (list == null)
{
return this.SimpleStyle;
}
else
{
return list.simple ? this.SimpleStyle : this.ComplexStyle;
}
}
}


Он практически аналогичен коду класса MyDTS, объявленному нами в параграфе 1.4.2.

В интерфейсном коде начальной страницы в тег <ComboBox>, создающий наш единственный список, добавим код, который укажет объект, выбирающий стиль для пункта:

<ComboBox . . .>
. . .
<ComboBox.ItemContainerStyleSelector>
<local:MySS>
<local:MySS.SimpleStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Background" Value="LightGreen"/>
</Style>
</local:MySS.SimpleStyle>
<local:MySS.ComplexStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Background" Value="LightPink"/>
</Style>
</local:MySS.ComplexStyle>
</local:MySS>
</ComboBox.ItemContainerStyleSelector>
</ComboBox>


Здесь для пунктов, представляющих простые списки, мы зададим светло-зелёный цвет фона, а для пунктов, представляющих сложные списки, - светло-розовый.

Проверим наше приложение в работе - и увидим, что разные пункты имеют разный цвет фона (рис. 8).


Рис. 8. Окно исправленного приложения ComboBox4. Различные пункты списка выводятся с применением разных стилей




2. ListBox: обычный список

Класс ListBox представляет обычный список. Он выводит выстроенный по вертикали набор пунктов, сформированных на основе коллекции каких-либо значений, что могут принадлежать к любому типу, и позволяет выбрать, в зависимости от настроек, либо только один пункт, либо их произвольное количество.


2.1. Базовые возможности обычного списка

Обычный список, как и его раскрывающийся "коллега", позволяет:

  • создавать набор пунктов на основе коллекции значений любого типа с применением привязки данных;
  • задавать коллекцию значений любого типа, на основе которых будут сформированы пункты, непосредственно в списке;
  • создавать пункты из объектов специализированного класса ListBoxItem, по возможностям полностью аналогичного классу ComboBoxItem;
  • задавать шаблоны и стили для всех пунктов;
  • указывать разные шаблоны и стили для разных пунктов на основании выполнения каких-либо условий.



Для всего этого используются те же программные средства, что применяются для работы с раскрывающимся списком.

Мы можем убедиться в этом самостоятельно.

Создадим проект ListBox1. У контейнера-сетки, что находится на начальной странице, создадим один столбец и одну строку, задав для них такие размеры, чтобы они растянулись на всё пространство страницы (то есть звёздочки):

<Grid . . .>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>


Поместим туда раскрывающийся список ListBox (в панели Панель элементов он находится в "ветви" Все элементы управления XAML). Зададим для него такие параметры:

  • Width - Auto;
  • Height - Auto;
  • Row - 0;
  • Column - 0;
  • RowSpan - 1;
  • ColumnSpan - 1;
  • HorizontalAlignment - Stretch;
  • VerticalAlignment - Stretch;
  • Margin - 10 пикселов со всех сторон.



Добавим в проект новые файлы программного кода PL.cs, MyDTS.cs и MySS.cs, в которых объявим уже знакомые нам классы PL, MyDTS и MySS. Код объявлений этих классов мы позаимствуем из проекта ComboBox4.

Из того же проекта мы можем взять интерфейсный код, создающий пункты списка, указывающий для них шаблоны и стили. Нам останется лишь заменить в нём имена класса: с ComboBox - на ListBox, а ComboBoxItem - на ListBoxItem.

Запустив приложение, мы увидим наш список (рис. 9). Он очень похож на раскрывающийся список из приложения ComboBox4.


Рис. 9. Окно приложения ListBox1




2.2. Режимы выбора и определение выбранных пунктов

Раскрывающийся список позволяет пользователю выбрать только один пункт. Однако обычный список, в зависимости от режима выбора, может дать возможность выбора сразу нескольких пунктов. Как задать режим выбора и как определить, какой пункт или пункты были выбраны, мы сейчас и выясним.

Для указания режима выбора в обычном списке применяется свойство SelectionMode класса ListBox. В качестве его значения задаётся один из элементов перечисления SelectionMode:

  • Single - пользователь может выбрать только один пункт списка (значение по умолчанию);
  • Extended - пользователь может выбирать произвольное количество пунктов, применяя клавиши-модификаторы <Shift> и <Ctrl>;
  • Multiple - пользователь может выбирать произвольное количество пунктов, не применяя никаких клавиш-модификаторов, а просто щёлкая мышью на пунктах.



Если список позволяет выбирать только один пункт, определить его мы можем с помощью уже знакомых нам по параграфу 1.2 свойств SelectedIndex, SelectedItem, SelectedValue, SelectedValuePath и события SelectionChanged. Здесь всё просто.

Создадим проект ListBox2. Зададим у имеющегося на начальной странице контейнера-сетки один столбец и две строки. Столбец мы растянем на всю ширину сетки, задав для него значение * в качестве ширины. Первая строка у нас также растянется на всю высоту родителя, а вторая получит такую высоту, чтобы только вместить своё содержимое. Напишем необходимый XAML-код самостоятельно.

Поместим на начальную страницу обычный список, задав для него те же параметры, что и у ранее созданного списка, и имя lstLs.

После этого добавим туда надпись с такими параметрами:

  • Имя - lblName;
  • Text - "" (пустая строка);
  • Width - Auto;
  • Height - Auto;
  • Row - 1;
  • Column - 0;
  • RowSpan - 1;
  • ColumnSpan - 1;
  • HorizontalAlignment - Stretch;
  • VerticalAlignment - Stretch;
  • Margin - 10 пикселов со всех сторон.



Зададим набор пунктов списка непосредственно в нём самом, написав такой XAML-код:

<ListBox . . .>
<x:String>XAML</x:String>
<x:String>C#</x:String>
<x:String>Visual Basic .NET</x:String>
<x:String>C++</x:String>
<x:String>JavaScript</x:String>
<x:String>TypeScript</x:String>
<x:String>Python</x:String>
<x:String>F#</x:String>
</ListBox>


Привяжем к событию SelectionChanged списка обработчик с таким кодом:

private void lstLs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.lblName.Text = (string)this.lstLs.SelectedItem;
}


Он просто заносит текст выбранного в списке пункта в надпись.

Запустим приложение, выберем в списке какой-либо пункт и проверим, появился ли его текст в надписи под списком (рис. 10).


Рис. 10. Окно приложения ListBox2. Пока поддерживается выбор только одного пункта



Если же список поддерживает выделение нескольких пунктов, следует обратиться к его свойству SelectedItems. Оно хранит объект-коллекцию, реализующую обобщённый интерфейс [url=https://msdn.microsoft.com/en-us/library/5y536ey6(v=vs.110).aspx]IList<T>[/url], которая, в свою очередь, содержит объекты, формирующие выбранные в данный момент пункты. Все объекты - элементы этой коллекции имеют тип object.

Давайте зададим для нашего списка режим множественного выделения. Для этого выделим его, в панели Свойства развернём категорию Общие, в ней найдём и развернём дополнительную секцию и в раскрывающемся списке SelectionMode, представляющем одноимённое свойство класса ListBox, выберем пункт Extended (или Multiple).

Исправим код обработчика события SelectionChanged следующим образом:

private void lstLs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
IList<object> si = this.lstLs.SelectedItems;
string s = "";
for (int i = 0; i < si.Count; i++)
{
if (i > 0)
{
s += ", ";
}
s += (string)si;
}
this.lblName.Text = s;
}


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

Запустим приложение. Выберем в списке несколько любых пунктов - и увидим внизу, в надписи, их перечень (рис. 11).


Рис. 11. Окно приложения ListBox2. Поддерживается выбор сразу нескольких пунктов



Вторым параметром методу - обработчику события SelectionChanged передаётся объект класса SelectionChangedEventArgs. Он поддерживает пару свойств, которые могут оказаться нам полезными:

  • AddedItems - хранит коллекцию объектов, формирующих пункты списка, которые были только что выбраны;
  • RemovedItems - хранит коллекцию объектов, формирующих пункты, к которых только что было снято выделение.



Коллекции, хранящиеся в этих свойствах, имеют тип IList<T>, а их элементы - тип object.


2.3. Указание другого контейнера для пунктов списка

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

Для указания такого контейнера применяется свойство ItemsPanel, унаследованное от класса-родителя ItemsControl. В качестве его значения указывается объект класса ItemsPanelTemplate, который и должен содержать описание нужного контейнера в виде XAML-кода.

Откроем проект ListBox1. Найдём тег <ListBox>, формирующий список, и запишем в него следующий код:

<ListBox . . .>
. . .
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>


Здесь мы указали в качестве контейнера для пунктов списка стопку с горизонтальной ориентацией и выравниванием по верхнему краю.

Теперь добавим в сам тег <ListBox> такие атрибуты:

<ListBox . . . ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollMode="Auto">

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

Полученный нами результат показан на рис. 12.


Рис. 12. Окно исправленного приложения ListBox1. В качестве контейнера пунктов списка используется стопка с горизонтальной ориентацией



Если список должен содержать много пунктов, вместо контейнера StackPanel рекомендуется использовать ItemsStackPanel. Он полностью аналогичен StackPanel, однако поддерживает повторное использование ранее созданных объектов ListBoxItem ради экономии системных ресурсов.

Замечание
Для вывода пунктов списка платформа UWP предусматривает ещё несколько контейнеров, но использовать их в обычных списках ListBox не допускается.


Дополнительные материалы




Владимир Дронов, MSInsider.ru Team
Май 2018

Комментарии

Комментариев нет...
Для возможности комментировать войдите в 1 клик через

По теме

Акции MSFT
108.7 +0.2
Акции торгуются с 17:30 до 00:00 по Москве
Мы на Facebook
Мы ВКонтакте
Сравнить цены на ноутбуки в Киеве.
В сервисе IPANN.NET купить прокси для SEO и SMM
Все права принадлежат © MSInsider.ru (ex TheVista.ru), 2017
Сайт является источником уникальной информации о семействе операционных систем Windows и других продуктах Microsoft. Перепечатка материалов возможна только с разрешения редакции.
Работает на WMS 2.34 (Страница создана за 0.08 секунд (Общее время SQL: 0.046 секунд - SQL запросов: 31 - Среднее время SQL: 0.00149 секунд))