c# - Autoscroll ListView in WPF using MVVM -
i try have list automatically scrolls end when adding new line.
here simple mvvm example in want integrate :
there button adds lines list when clicked.
model code :
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 { { lock (_threadlock) if (current == null) current = new studentsmodel(); return current; } } private studentsmodel() { (int = 1; <= 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); } }
viewmodel code :
public class mainviewmodel : viewmodelbase { public studentsmodel students { get; set; } public mainviewmodel() { students = studentsmodel.current; } private icommand _addstudent; public icommand addstudent { { if (_addstudent == null) { _addstudent = new delegatecommand(delegate() { students.addastudent("new student lastname", "new student firstname"); }); } return _addstudent; } }
view code :
<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>
thank you
i wrote simple attachedproperty use auto-scroll bottom when bound observablecollection changes:
public class autoscroller : behavior<scrollviewer> { public object autoscrolltrigger { { 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 autoscroller; if( ts == null ) return; // must attached scrollviewer var sv = ts.associatedobject scrollviewer; // check if attached observablecollection, in case // subscribe collectionchanged scroll when stuff added/removed var ncol = args.newvalue inotifycollectionchanged; // new event handler if( ncol != null ) ncol.collectionchanged += ts.oncollectionchanged; // remove old eventhandler var ocol = args.oldvalue inotifycollectionchanged; if( ocol != null ) ocol.collectionchanged -= ts.oncollectionchanged; // scroll bottom when bound object changes if( sv != null && ts.autoscroll ) sv.scrolltobottom(); } private void oncollectionchanged(object sender, eventargs args) { app.current.dispatcher.invoke(delegate { (this.associatedobject scrollviewer).scrolltobottom(); }); } }
note: use rx subscribe collectionchanged event, can done normal .net event handling plus dispatcher.invoke .scrolltobottom() call on ui thread.
also note: attached property in behavior class called touchscroller, other stuff too, can simplified simple attached property.
edit:
to use it, in xaml bind property viewmodel:
<scrollviewer ...> <i:interaction.behaviors> <util:touchscroller autoscrolltrigger="{binding students}" /> </i:interaction.behaviors> ... </scrollviewer>
edit2:
i edited code contain full behavior. use behavior instead of simpley static class attached behavior because gives access .associatedobject
, scrollviewer need call .scrolltobottom()
on. without using behavior, have keep track of these objects manually. removed rx subscription , added simple event handlers , dispatcher.invoke.
this stripped down , modified version of use, haven't tested version.
Comments
Post a Comment