WPF MVVM模式下实现ListView下拉显示更多内容

2021-05-14 11:28

阅读:601

标签:key   resource   logs   ret   分享   false   command   一个   readonly   

在手机App中,如果有一个展示信息的列表,通常会展示很少一部分,当用户滑动到列表底部时,再加载更多内容。这样有两个好处,提高程序性能,减少网络流量。这篇博客中,将介绍如何在WPF ListView中实现这个功能。

实现思路:为ListView新增一个附加属性,用来绑定当下拉到底部时触发增加列表内容的功能。

XAML:

技术分享
     local:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}">
            
技术分享

ScrollViewerMonitor:

技术分享
public class ScrollViewerMonitor
    {
        public static ICommand GetAtEndCommand(DependencyObject obj)
        {
            return (ICommand)obj.GetValue(AtEndCommandProperty);
        }

        public static void SetAtEndCommand(DependencyObject obj, ICommand value)
        {
            obj.SetValue(AtEndCommandProperty, value);
        }

        public static readonly DependencyProperty AtEndCommandProperty =
            DependencyProperty.RegisterAttached("AtEndCommand", typeof(ICommand), 
                typeof(ScrollViewerMonitor), new PropertyMetadata(OnAtEndCommandChanged));

        public static void OnAtEndCommandChanged(
            DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)d;
            if (element != null)
            {
                element.Loaded -= element_Loaded;
                element.Loaded += element_Loaded;
            }
        }

        private static void element_Loaded(object sender, RoutedEventArgs e)
        {
            FrameworkElement element = (FrameworkElement)sender;

            element.Loaded -= element_Loaded;

            ScrollViewer scrollViewer = FindChildOfType(element);

            if(scrollViewer == null)
            {
                throw new InvalidOperationException("ScrollViewer not found.");
            }

            scrollViewer.ScrollChanged += delegate 
            {
                bool atBottom = scrollViewer.VerticalOffset 
                                 >= scrollViewer.ScrollableHeight;

                if(atBottom)
                {
                    var atEnd = GetAtEndCommand(element);
                    if(atEnd != null)
                    {
                        atEnd.Execute(null);
                    }
                }
            };
        }

        private static T FindChildOfType(DependencyObject root) where T : class
        {
            var queue = new Queue();
            queue.Enqueue(root);

            while (queue.Count > 0)
            {
                DependencyObject current = queue.Dequeue();
                for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 
技术分享

MainViewModel:

技术分享
public class MainViewModel : INotifyPropertyChanged
    {
        public MainViewModel()
        {
            _busy = false;

            AddMoreItems();

            fetchMoreDataCommand = new DelegateCommand(() => {

                ThreadPool.QueueUserWorkItem(
                    delegate
                    {
                        Busy = true;

                        Thread.Sleep(3000);

                        App.Current.Dispatcher.BeginInvoke(new Action(()=> {

                            AddMoreItems();

                            Busy = false;

                        }));
                    });
            });
        }

        private void AddMoreItems()
        {
            int start = items.Count;
            int end = start + 10;
            for (int i = start; i  items = new ObservableCollection();

        public ObservableCollection Items
        {
            get
            {
                return items;
            }
        }

        private bool _busy;

        public bool Busy
        {
            get
            {
                return _busy;
            }

            set
            {
                if(_busy != value)
                {
                    _busy = value;

                    OnPropertyChanged("Busy");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
技术分享

Busy属性用来决定是否显示Loading。

运行效果:

技术分享

感谢您的阅读!代码点击这里下载。

WPF MVVM模式下实现ListView下拉显示更多内容

标签:key   resource   logs   ret   分享   false   command   一个   readonly   

原文地址:http://www.cnblogs.com/wangchaoyuana/p/7523426.html


评论


亲,登录后才可以留言!