WPF技巧20190722 LIstbox/ListView 自动流动到数据最后一行
一.需求:
我们在利用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}" />
本文介绍了在WPF中使用ListView和ListBox显示动态增加数据时,如何自动滚动到最后一行的两种方法。第一种方法是通过ViewModel中的委托和ScrollIntoView方法实现,第二种方法是通过创建附加属性监听集合变化并触发滚动。
4877

被折叠的 条评论
为什么被折叠?



