Bắt sự kiện ScrollChanged

Trong các controller của WPF như DataGrid, ListView ... để bắt sự kiện khi cuộn thì khai báo bắt sự kiện bằng thuộc tính ScrollViewer.ScrollChanged
Ví dụ ListView sau sẽ bắt sự kiện khi các phần tử của nó cuộn lên/xuống
<ListView Name="listview" ScrollViewer.ScrollChanged="listview_ScrollChanged" />
Trong đó listview_ScrollChanged là code xử lý khi nhận được sự kiện, nó có cấu trúc dạng:
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    //...
}

Bật/tắt bắt sự kiện ScrollChanged sử dụng AddHandler/RemoveHandler

Ngoài cách khai báo trong XAML như trên, nếu muốn linh hoạt hơn, có thể dễ dàng kích hoạt khi nào muốn bắt sự kiện ScrollChanged, khi nào không muốn bắt thì dùng cách sau, vì dụ đã khai báo một ListView tên listview:
1) Khai báo một Delegate lưu giữ xử lý sự kiện
private Delegate listviewscrollhandler;
2) Khai báo một phương thức giống với cấu trúc nhận sự kiện ScrollViewer.ScrollChangedEvent
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    //code như nhận được ScrollChanged
}
3) Khi khởi tạo Controller, thì khởi tạo giá trị hàm gán cho Delegate trên
listviewscrollhandler = new ScrollChangedEventHandler(ScrollViewer_ScrollChanged);
4) Khi nào muốn listview bắt đầu nhận sự kiện ScrollChanged thì thêm vào:
listview.AddHandler(ScrollViewer.ScrollChangedEvent, listviewscrollhandler);
5) Khi nào muốn listview không nhận ScrollChanged thì thêm vào:
listview.RemoveHandler(ScrollViewer.ScrollChangedEvent, listviewscrollhandler);

Nhận biết khi phần tử cuối trong ListView, DataGrid ... cuộn tới phần tử cuối

Khi phần tử cuối được cuộn đến, nghĩa là nó đang hiện thị trên giao diện - vậy chỉ cần kiểm tra việc này:
private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
    if ((e.VerticalChange > 0)) //Cuộn xuống
    {
        object item_end = listview.Items[listview.Items.Count - 1];
        ListViewItem listview_item_end =
            (ListViewItem)listview.ItemContainerGenerator.ContainerFromItem(item_end);

        if (item_end != null)
        {
            //CÓ CUỘN TỚI PHẦN TỬ CUỐI
        }
    }
}

Ví dụ

Sử dụng ListView, hiện thị khởi đầu 100 phần tử. Khi cuộn tới phần tử cuối thì đổ thêm 100 phần tử nữa vào ListView ..., code như sau:
Window.xaml
<Window x:Class="ScrollEndItem.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:ScrollEndItem"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="300">
    <ListView Name="listview"  />
</Window>
Window.xaml.cs
namespace ScrollEndItem
{
public partial class MainWindow : Window
{

    private Delegate listviewscrollhandler;

    public MainWindow()
    {
        InitializeComponent();

        //Tạo Delegate nhận sự kiện khi cuộn
        listviewscrollhandler = new ScrollChangedEventHandler(ScrollViewer_ScrollChanged);

        //Bắt sự kiện ScrollViewer.ScrollChangedEvent
        listview.AddHandler(ScrollViewer.ScrollChangedEvent, listviewscrollhandler);

        Add100item();
    }

    void Add100item()
    {
        for (int i = 0; i < 100; i++)
        {
            listview.Items.Add(new ListViewItem()
            {
                Content = $"Phần tử {listview.Items.Count + 1}"
            });
        }
    }
    private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        //Không bắt scroll khi đang xử lý
        listview.RemoveHandler(ScrollViewer.ScrollChangedEvent, listviewscrollhandler);

        if ((e.VerticalChange > 0))
        {
            object item_end = listview.Items[listview.Items.Count - 1];
            ListViewItem listview_item_end =
                (ListViewItem)listview.ItemContainerGenerator.ContainerFromItem(item_end);

            if (listview_item_end != null)
            {
                Add100item();
                listview.UpdateLayout();
            }
        }

        //Thêm scroll sau khi xử lý xong
        listview.AddHandler(ScrollViewer.ScrollChangedEvent, listviewscrollhandler);
    }

}
}
Chạy ví dụ trên, mỗi khi ListView cuộn tới cuối, sẽ có thêm 100 phần tử thêm vào.
WPF

Đăng ký nhận bài viết mới