Содержание
При ограниченном пространстве окна программы нам периодически необходимо обеспечить прокрутку содержимого этого окна. Например, когда в окне программы размещается большое количество элементов управления или загружен текст большого объема. Для таких случаев в WPF используется элемент ScrollViewer
, который и обеспечивает прокрутку содержимого.
Элемент ScrollViewer
Элемент ScrollViewer
представляет собой контейнер содержимого с двумя полосами прокрутки — горизонтальной и вертикальной. ScrollViewer
может содержать только один контейнер содержимого и, при этом, в качестве такого контейнера обычно выступает какой-либо предок элемента Panel
(WrapPanel
, StackPanel
и т.д.). Рассмотрим следующий пример:
<Window x:Class="WpfApp1.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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid> <ScrollViewer> <StackPanel> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Red"></Border> <Border Height="50" Background="Yellow"></Border> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Yellow"></Border> <Border Height="50" Background="Blue"></Border> </StackPanel> </ScrollViewer> </Grid> </Window>
Здесь мы используем ScrollViewer с настройками по умолчанию, поэтому в запущенном приложении вы увидите следующее окно приложения:
Несмотря на то, что элементам Border
внутри контейнера вполне хватает места. чтобы разместиться в нем и быть полностью видимыми, у ScrollViewer
мы видим вертикальную полосу прокрутки, которая в данный момент неактивна. Измените высоту окна и вы увидите, что полоса прокрутки становится доступной и можно прокручивать содержимое контейнера.
При этом, сколько бы мы не изменяли ширину окна — горизонтальная полоса прокрутки не появляется, так как все элементы внутри ScrollViewer
автоматически меняют свою ширину. Рассмотрим основные свойства и методы ScrollViewer
.
Свойства и события ScrollViewer
Среди основных свойств элемента ScrollViewer
можно выделить следующие:
Свойство | Тип | Описание |
HorizontalScrollBarVisibility |
ScrollBarVisibility |
Определяет видимость горизонтальной полосы прокрутки и может принимать следующие значения:
|
VerticalScrollBarVisibility |
ScrollBarVisibility |
Определяет видимость вертикальной полосы прокрутки. Возможные принимаемые значения см. выше. |
HorizontalOffset |
double |
Возвращает горизонтальное смещение прокручиваемого содержимого. Свойство только для чтения. |
VerticalOffset |
double |
Возвращает вертикальное смещение прокручиваемого содержимого. Свойство только для чтения. |
Также, элемент ScrollViewer
предоставляет нам следующее событие
Событие | Описание |
public eventScrollChangedEventHandler ScrollChanged; |
Генерируется при обнаружении изменений положения полосы прокрутки или размера области просмотра. |
Изменим код нашего приложения следующим образом:
1. Перепишем разметку XAML окна:
<Window x:Class="WpfApp1.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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <ScrollViewer x:Name="scroll" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="scroll_ScrollChanged"> <StackPanel Width="700" Height="400"> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Red"></Border> <Border Height="50" Background="Yellow"> <TextBlock x:Name="info"/> </Border> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Yellow"></Border> <Border Height="50" Background="Blue"></Border> </StackPanel> </ScrollViewer> </Window>
Во-первых, мы определили размеры контейнера StackPanel
внутри ScrollViewer
:
<StackPanel Width="700" Height="400">
Во-вторых, мы добавили текстовый блок с именем info
для вывода информации о значении свойств ScrollViewer
:
<Border Height="50" Background="Yellow"> <TextBlock x:Name="info"/> </Border>
И, в-третьих, определили значение свойств HorizontalScrollBarVisibility
, VerticalScrollBarVisibility
и обработчик события ScrollChanged
:
<ScrollViewer x:Name="scroll" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="scroll_ScrollChanged">
Теперь полосы прокрутки будут показываться только, когда содержимому не будет хватать места в окне просмотра, а обработчик события будет следующим:
private void scroll_ScrollChanged(object sender, ScrollChangedEventArgs e) { info.Text = $"HorizontalOffset {scroll.HorizontalOffset}; VerticalOffset {scroll.VerticalOffset}"; }
Запустим приложение и посмотрим на результат. При запуске приложения, всё содержимое полностью умещается и видимо в окне просмотра, поэтому полос прокрутки мы не видим:
Изменим размер окна таким образом, чтобы увидеть полосы прокрутки и изменим положение «бегунков»:При необходимости, мы можем управлять прокруткой в
ScrollViewer
автоматически, используя методы элемента.
Методы для программной прокрутки ScrollViewer
Для программной прокрутки ScrollViewer
можно использовать следующие методы (в таблице представлена только часть методов):
Метод | Описание |
public void LineDown(); |
Прокрутка вниз на одну строку (обычно, на 16 единиц) |
public void LineUp(); |
Прокрутка вверх на одну строку |
public void LineLeft(); |
Прокрутка влево на одну строку |
public void LineRight(); |
Прокрутка вправо на одну строку |
public void PageDown(); |
Прокрутка на страницу вниз |
public void PageLeft(); |
Прокрутка на страницу влево |
public void PageRight(); |
Прокрутка на страницу вправо |
public void PageUp(); |
Прокрутка на страницу вверх |
public void ScrollToHorizontalOffset(double offset); |
Прокрутка влево или вправо на определенное значение |
public void ScrollToVerticalOffset(double offset); |
Прокрутка вверх или вниз на определенное значение |
ScrollToEnd() |
Прокрутка в конец окна |
ScrollToHome() |
Прокрутка в самый вверх окна |
Все эти методы можно сгруппировать по трем группам:
- Прокрутка на элемент (методы вида
Line[Up, Down, Left, Right]()
) - Прокрутка на страницу (методы вида
Page[Up, Down, Left, Right]()
) - Прокрутка на определенное значение (методы вида
ScrollTo
)
Чтобы продемонстрировать работу этих методов, перепишем код нашего приложения следующим образом:
<Window x:Class="WpfApp1.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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <StackPanel Orientation="Vertical"> <ScrollViewer x:Name="scroll" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="scroll_ScrollChanged" Height="400"> <StackPanel Width="700" Height="400"> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Red"></Border> <Border Height="50" Background="Yellow"> <TextBlock x:Name="info"/> </Border> <Border Height="50" Background="Blue"></Border> <Border Height="50" Background="Green"></Border> <Border Height="50" Background="Yellow"></Border> <Border Height="50" Background="Blue"></Border> </StackPanel> </ScrollViewer> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Content="Вверх" Grid.Column="0" Margin="4" Click="Button_Click" /> <Button Content="Вниз" Grid.Column="1" Margin="4" Click="Button_Click_1" /> <Button Content="Влево" Grid.Column="2" Margin="4" Click="Button_Click_2" /> <Button Content="Вправо" Grid.Column="3" Margin="4" Click="Button_Click_3"/> </Grid> </StackPanel> </Window>
Здесь мы добавили контейнер Grid
с четырьмя кнопками для программной прокрутки ScrollViewer
вверх, вниз, вправо и влево:
<Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Button Content="Вверх" Grid.Column="0" Margin="4" Click="Button_Click" /> <Button Content="Вниз" Grid.Column="1" Margin="4" Click="Button_Click_1" /> <Button Content="Влево" Grid.Column="2" Margin="4" Click="Button_Click_2" /> <Button Content="Вправо" Grid.Column="3" Margin="4" Click="Button_Click_3"/> </Grid>
У каждой из кнопок мы определили обработчики события Click
. В этих обработчиках мы будем использовать методы из той или иной группы для прокрутки. Например,
private void Button_Click(object sender, RoutedEventArgs e) { scroll.LineUp(); } private void Button_Click_1(object sender, RoutedEventArgs e) { scroll.LineDown(); } private void Button_Click_2(object sender, RoutedEventArgs e) { scroll.LineLeft(); } private void Button_Click_3(object sender, RoutedEventArgs e) { scroll.LineRight(); }
Запустим приложение и попробуем, управляя кнопками выполнить прокрутку:Прокрутка с помощью методов типа
Line...()
осуществляет переход к следующему элементу в логическом дереве. Обычно, смещение идет на 16 единиц в заданном направлении. Немного по другому работают методы прокрутки на страницу.
Изменим обработчики кнопок следующим образом:
private void Button_Click(object sender, RoutedEventArgs e) { scroll.PageUp(); } private void Button_Click_1(object sender, RoutedEventArgs e) { scroll.PageDown(); } private void Button_Click_2(object sender, RoutedEventArgs e) { scroll.PageLeft(); } private void Button_Click_3(object sender, RoutedEventArgs e) { scroll.PageRight(); }
А также изменим высоту ScrollViewer
, установив её равной 100:
<ScrollViewer x:Name="scroll" ... Height="100"> ... </ScrollViewer>
Теперь запустите приложение и убедитесь, что ScrollViewer
пытает прокрутить содержимое на размер своей высоты (или ширины) или же, если оставшееся расстояние прокрутки меньше этого значения, то прокрутка идёт до конца:И, наконец, продемонстрируем прокрутку на произвольное значение. Изменим обработчики кнопок следующим образом:
private void Button_Click(object sender, RoutedEventArgs e) { scroll.ScrollToVerticalOffset(-25); } private void Button_Click_1(object sender, RoutedEventArgs e) { scroll.ScrollToVerticalOffset(25); } private void Button_Click_2(object sender, RoutedEventArgs e) { scroll.ScrollToHorizontalOffset(25); } private void Button_Click_3(object sender, RoutedEventArgs e) { scroll.ScrollToHorizontalOffset(-25); }
Обратите внимание, что для прокрутки вверх и влево мы используем отрицательные значения смещения, а для прокрутки вниз и влево — положительные. При этом, прокрутка производится один раз, то есть, сколько бы раз мы не нажимали на кнопку — величина прокрутки не изменится после первого нажатия. Поэтому, если вам необходимо программно прокручивать содержимое ScrollViewer
на произвольное значение, то необходимо изменить код обработчиков следующим образом (на примере прокрутки вверх и вниз)
private void Button_Click(object sender, RoutedEventArgs e) { scroll.ScrollToVerticalOffset(scroll.ContentVerticalOffset - 25); } private void Button_Click_1(object sender, RoutedEventArgs e) { scroll.ScrollToVerticalOffset(scroll.ContentVerticalOffset + 25); }
Теперь текущее значение прокрутки будет браться из свойства scroll.ContentVerticalOffset
и можно программно пролистывать ScrollViewer
на 25 единиц в обоих направлениях до конца.
Итого
Элемент ScrollViewer
позволяет организовать прокрутку содержимого, когда оно полностью не умещается в доступную область просмотра. Прокрутка может осуществляться как с использование полос прокрутки, так и программно на один элемент, на страницу или на произвольное значение.