我尝试创建一个在添加新行时自动滚动到末尾的列表。
这是一个简单的 MVVM 示例,我想在其中集成:
有一个按钮可以在单击时将行添加到列表中。
型号代码:
public class Student
{
public string Lastname {get; set;}
public string Firstname {get; set;}
public Student(string lastname, string firstname) {
this.Lastname = lastname;
this.Firstname = firstname;
}
}
public class StudentsModel: ObservableCollection<Student>
{
private static object _threadLock = new Object();
private static StudentsModel current = null;
public static StudentsModel Current {
get {
lock (_threadLock)
if (current == null)
current = new StudentsModel();
return current;
}
}
private StudentsModel() {
for (int i = 1; i <= 50; i++)
{
Student aStudent = new Student("Student " + i.ToString(), "Student " + i.ToString());
Add(aStudent);
}
}
public void AddAStudent(String lastname, string firstname) {
Student aNewStudent = new Student(lastname, firstname);
Add(aNewStudent);
}
}
View 模型代码:
public class MainViewModel : ViewModelBase
{
public StudentsModel Students { get; set; }
public MainViewModel()
{
Students = StudentsModel.Current;
}
private ICommand _AddStudent;
public ICommand AddStudent
{
get
{
if (_AddStudent == null)
{
_AddStudent = new DelegateCommand(delegate()
{
Students.AddAStudent("New Student lastname", "New Student firstname");
});
}
return _AddStudent;
}
}
查看代码:
<Window x:Class="demo.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:demo.Commands">
<Grid>
<ListView Grid.Row="2" BorderBrush="White" ItemsSource="{Binding Path=Students}"
HorizontalAlignment="Stretch">
<ListView.View>
<GridView>
<GridViewColumn Header="Lastname" DisplayMemberBinding="{Binding Path=Lastname}" />
<GridViewColumn Header="Firstname" DisplayMemberBinding="{Binding Path=Firstname}" />
</GridView>
</ListView.View>
</ListView >
<Button Content="Add" Command="{Binding AddStudent}" Margin="601.94,36.866,96.567,419.403" />
</Grid>
谢谢
最佳答案
我编写了一个简单的 AttachedProperty,用于在绑定(bind)的 ObservableCollection 更改时自动滚动到底部:
public class AutoScroller : Behavior<ScrollViewer>
{
public object AutoScrollTrigger
{
get { return (object)GetValue( AutoScrollTriggerProperty ); }
set { SetValue( AutoScrollTriggerProperty, value ); }
}
public static readonly DependencyProperty AutoScrollTriggerProperty =
DependencyProperty.Register(
"AutoScrollTrigger",
typeof( object ),
typeof( AutoScroller ),
new PropertyMetadata( null, ASTPropertyChanged ) );
private static void ASTPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs args )
{
var ts = d as AutoScroller;
if( ts == null )
return;
// must be attached to a ScrollViewer
var sv = ts.AssociatedObject as ScrollViewer;
// check if we are attached to an ObservableCollection, in which case we
// will subscribe to CollectionChanged so that we scroll when stuff is added/removed
var ncol = args.NewValue as INotifyCollectionChanged;
// new event handler
if( ncol != null )
ncol.CollectionChanged += ts.OnCollectionChanged;
// remove old eventhandler
var ocol = args.OldValue as INotifyCollectionChanged;
if( ocol != null )
ocol.CollectionChanged -= ts.OnCollectionChanged;
// also scroll to bottom when the bound object itself changes
if( sv != null && ts.AutoScroll )
sv.ScrollToBottom();
}
private void OnCollectionChanged(object sender, EventArgs args)
{
App.Current.Dispatcher.Invoke(delegate {
(this.AssociatedObject as ScrollViewer).ScrollToBottom();
});
}
}
注意:我使用 Rx 订阅 CollectionChanged 事件,但这可以通过正常的 .NET 事件处理加上 Dispatcher.Invoke 来获得 UI 线程上的 .ScrollToBottom() 调用来完成。
另请注意:此附加属性位于名为 TouchScroller 的 Behavior 类中,该类也可以执行其他操作,但可以将其简化为仅是一个简单的附加属性。
编辑:
要使用它,在 xaml 中,您只需绑定(bind) View 模型中的属性:
<ScrollViewer ...>
<i:Interaction.Behaviors>
<util:TouchScroller AutoScrollTrigger="{Binding Students}" />
</i:Interaction.Behaviors>
...
</ScrollViewer>
EDIT2:
我编辑了代码以包含完整的行为。我使用 Behavior 而不是简单的带有附加行为的静态类,因为它可以访问
.AssociatedObject
,也就是需要调用.ScrollToBottom()
的ScrollViewer在。如果不使用行为,您将不得不手动跟踪这些对象。我还删除了 Rx 订阅并添加了简单的事件处理程序和 Dispatcher.Invoke。这是我使用的精简和修改版本,但我还没有测试过这个版本。
关于c# - 使用 MVVM 在 WPF 中自动滚动 ListView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23963315/