WPF技巧20190722 使用附加属性,使 LIstbox/ListView 自动滚动到数据最后一行

本文介绍了在WPF中使用ListView和ListBox显示动态增加数据时,如何自动滚动到最后一行的两种方法。第一种方法是通过ViewModel中的委托和ScrollIntoView方法实现,第二种方法是通过创建附加属性监听集合变化并触发滚动。

一.需求:

我们在利用ListView或者ListBox来显示不断增加的数据时,总是希望能看到最新增加到行尾的一行最新数据。实现这个需求,使用传统的方式并不难,而使用MVVM模式进行数据绑定实现,就要依靠为控件增加附加属性的方法来实现.

二. 实现方式

1. 实现方式一

(摘自网页,原文标题:WPF ListBox如何实现动态加载数据,并且滚动条自动下拉)
WPF ListBox如何实现动态加载数据,并且滚动条自动下拉

1.1 绑定

ListBox绑定ViewModel中的string链表,注意不能用普通的List,需要定义ObservableCollection(如果用List,界面刷新会有所延迟)

XAML(DataContext为viewModel):

<ListBox x:Name="StatusList" ItemsSource="{Binding ListStatus}" />

ViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.IO;
using System.IO.Ports;
using System.Data;
using System.Windows.Threading;

namespace SPT
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }

       
        private ObservableCollection<string> listStatus = new ObservableCollection<string> { };
        public ObservableCollection<string> ListStatus
        {
            get { return listStatus; }
            set
            {
                listStatus = value;
                OnPropertyChanged(new PropertyChangedEventArgs("ListStatus"));
            }
        }

    }
}

1.2 自动滚动

ListBox有ScrollIntoView方法,但是在ViewModel中添加删除ListStatus时,不能直接调用此方法,故要增加一个委托定义,以控制界面元素:

1.2.1 ViewModel中定义更改列表方法:
        /// <summary>
        /// 增加状态信息到列表里
        /// </summary>
public void AddItemsToStatus(bool isCommand, string strStatus)
        {
            ListStatus.Add(strStatus);
            FocusLastItem();
        }
        /// <summary>
        /// 委托定义,用于控制界面元素
        /// </summary>
        public delegate void ScrollToEnd();
        public ScrollToEnd FocusLastItem = null;
1.2.2 在主界面后台代码中增加自动滚动条方法:
        public MainWindow()
        {
            InitializeComponent();
            ViewModel vm= (ViewModel)this.DataContext;
            vm.FocusLastItem += AutoScroll;
        }
       
        /// <summary>
        /// 滚动条自动滚动
        /// </summary>
        private void AutoScroll()
        {
            StatusList.ScrollIntoView(StatusList.Items[StatusList.Items.Count - 1]);
        }

2 实现方式二:增加附加属性

网上有引用using System.Windows.Interactivity; 附加属性时继承Behavior的做法.以方便利用其

AssociatedObject 方法查找放置行为的元素,但一直没测试成功.

public class AutoScroller : Behavior<ListView>
{
//..省略若干..
}
 // 通过AssociatedObject访问放置行为的元素ListView
 //var sv = ts.AssociatedObject as ListView ;

我的实现方法如下

2.1 新建类,定义附加属性

快捷键 propa

基本思路: 在类中定义一个AutoScrollTrigger属性,并指定一个回调方法ScrollEventCallBack.通过该方法,为该类指定一个私有对象View,也就是ListView对象.
当AutoScrollTrigger属性值发生变化时,判断该值是否为ObserableCollection集合(是否具有INotifyCollectionChanged特性),并为该集合绑定OnChanged事件以及实现OnChanged的方法
Onchanged事件中,定位集合最后一个对象,并利用view.ScrollIntoView(lastItem)方法滚动到最后数据对象的位置
;

using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
//using System.Windows.Interactivity;
//using System.Windows.Interactivity;

namespace Sprider_1688AliZs
{
    public class AutoScroller : DependencyObject
    {
      
        private static ListView view;

        public static object GetAutoScrollTrigger(DependencyObject obj)
        {
            return (object)obj.GetValue(AutoScrollTriggerProperty);
        }

        public static void SetAutoScrollTrigger(DependencyObject obj, object value)
        {
            obj.SetValue(AutoScrollTriggerProperty, value);
        }


        // Using a DependencyProperty as the backing store for AutoScrollTrigger.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AutoScrollTriggerProperty =
            DependencyProperty.RegisterAttached("AutoScrollTrigger",
                typeof(object),
                typeof(AutoScroller),
                new PropertyMetadata(null, ScrollEventCallBack));

        private static void ScrollEventCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            view = d as ListView;

            // 检查我们是否附加到ObservableCollection,在这种情况下订阅CollectionChanged,以便在添加/删除内容时滚动
            var newCollect = e.NewValue as INotifyCollectionChanged;

            // 订阅新事件 数据集变化时 
            if (newCollect != null)
                newCollect.CollectionChanged += OnCollectionChanged;

            // 取消订阅事件
            var oldCollect = e.OldValue as INotifyCollectionChanged;

            if (oldCollect != null)
                oldCollect.CollectionChanged -= OnCollectionChanged;

        }


        private static void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            System.Collections.IList list = e.NewItems;
            var lastItem = list[list.Count - 1];

            App.Current.Dispatcher.Invoke(delegate
            {
                view.ScrollIntoView(lastItem);
            });
        }
    }
}



2.2 窗口引用

ViewCode

<ListView x:Name="CategoryList" ItemsSource="{Binding UrlList}"  
                  local:AutoScroller.AutoScrollTrigger="{Binding UrlList}"  />


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值