我有一个非常简单的问题,但我无法弄清楚如何使用MVVM破解它。
我有ListBox
绑定到ObservableCollection<string>
。
我运行的流程会将大量项目添加到集合中,因此它们会显示在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());
}
}
}
答案 0 :(得分:19)
您可以创建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
换成自定义的标准{/ p>
<custom:ScrollingListBox Margin="10" Height="150"
ItemsSource="{Binding Path=MyValue}" />
答案 1 :(得分:12)
您还可以添加行为:
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]);
}
}
}