列表框滚动到带有 MVVM 的视图中
本文关键字:MVVM 视图 滚动 列表 | 更新日期: 2023-09-27 18:16:41
我有一个非常简单的问题,但我无法弄清楚如何使用MVVM破解它。
我有一个绑定到ObservableCollection<string>
的ListBox
.
我运行一个过程,将一大堆项目添加到集合中,因此它们显示在ListBox
中。
问题是,随着项目添加到列表框中...滚动条只是增长,但我似乎无法弄清楚如何为添加到集合中的每个项目ScrollIntoView
。
此示例代码完美地说明了这个问题。
XAML
<Window x:Class="Stack.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Stack"
Title="MainWindow"
Height="350"
Width="525">
<Window.DataContext>
<vm:MainWindowViewModel />
</Window.DataContext>
<StackPanel>
<ListBox Margin="10" Height="150"
ItemsSource="{Binding Path=MyValue}" />
<Button Margin="10"
Height="25"
Content="Generate"
Command="{Binding Path=CommandName}" />
</StackPanel>
</Window>
查看模型
namespace Stack
{
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows.Input;
using GalaSoft.MvvmLight.Command;
/// <summary>
/// TODO: Update summary.
/// </summary>
public class MainWindowViewModel : INotifyPropertyChanged
{
private readonly BackgroundWorker _worker;
private ICommand _commandName;
private ObservableCollection<string> _myValue = new ObservableCollection<string>();
/// <summary>
/// Initializes a new instance of the <see cref="MainWindowViewModel" /> class.
/// </summary>
public MainWindowViewModel()
{
this._worker = new BackgroundWorker();
this._worker.DoWork += new DoWorkEventHandler(DoWork);
this._worker.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
this._worker.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e)
{
CommandManager.InvalidateRequerySuggested();
};
}
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
public ICommand CommandName
{
get
{
if (this._commandName == null)
{
this._commandName = new RelayCommand(() => this.CommandMethod());
}
return this._commandName;
}
}
/// <summary>
/// Gets or sets my value.
/// </summary>
/// <value>My value.</value>
public ObservableCollection<string> MyValue
{
get
{
return this._myValue;
}
set
{
this._myValue = value;
this.NotifyPropertyChange("MyValue");
}
}
/// <summary>
/// Notifies the property change.
/// </summary>
/// <param name="propName">Name of the prop.</param>
internal void NotifyPropertyChange(string propName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
/// <summary>
/// Commands the method.
/// </summary>
private void CommandMethod()
{
this.MyValue.Clear();
this._worker.RunWorkerAsync();
this._worker.WorkerReportsProgress = true;
}
/// <summary>
/// Does the work.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs" /> instance containing the event data.</param>
private void DoWork(object sender, DoWorkEventArgs e)
{
this.Populate();
}
/// <summary>
/// Populates this instance.
/// </summary>
private void Populate()
{
for (int index = 0; index < 100; index++)
{
System.Threading.Thread.Sleep(10);
this._worker.ReportProgress(index);
}
}
/// <summary>
/// Progresses the changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.ComponentModel.ProgressChangedEventArgs" /> instance containing the event data.</param>
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.MyValue.Add(e.ProgressPercentage.ToString());
}
}
}
您可以创建一个DependencyProperty
,或者只是扩展ListBox
控件并改用新控件。
public class ScrollingListBox : ListBox
{
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
int newItemCount = e.NewItems.Count;
if(newItemCount > 0)
this.ScrollIntoView(e.NewItems[newItemCount - 1]);
base.OnItemsChanged(e);
}
}
在 XAML 中,添加类的命名空间:
xmlns:custom="clr-namespace:ScrollingListBoxNamespace"
并将您的标准ListBox
换成您的自定义:
<custom:ScrollingListBox Margin="10" Height="150"
ItemsSource="{Binding Path=MyValue}" />
您还可以添加行为:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
.
.
.
<ListBox Margin="10" Height="150" ItemsSource="{Binding Path=MyValue}" >
<i:Interaction.Behaviors>
<bhv:ScrollIntoViewBehavior/>
</i:Interaction.Behaviors>
</ListBox>
并实现行为:
using System.Windows.Interactivity;
public class ScrollIntoViewBehavior : Behavior<ListBox>
{
protected override void OnAttached()
{
ListBox listBox = AssociatedObject;
((INotifyCollectionChanged)listBox.Items).CollectionChanged += OnListBox_CollectionChanged;
}
protected override void OnDetaching()
{
ListBox listBox = AssociatedObject;
((INotifyCollectionChanged)listBox.Items).CollectionChanged -= OnListBox_CollectionChanged;
}
private void OnListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ListBox listBox = AssociatedObject;
if (e.Action == NotifyCollectionChangedAction.Add)
{
// scroll the new item into view
listBox.ScrollIntoView(e.NewItems[0]);
}
}
}