WPF:将VlistView自动滚动到最后一项



因此,在我的应用程序中,我打开特定的进程,读取其输出并将其放入我的ListView:中

<ListView Name="listViewResults"
ItemsSource="{Binding Results}"/>

ViewModel

private ObservableCollection<string> results;

过程输出

private void OutputHandler(object sender, DataReceivedEventArgs e)
{
if (line != null)
{
results.Add(line);
}    
}

所以我创建了另一个property:

private string currentLog;
public string CurrentLog
{
get { return currentLog; }
set
{
currentLog = value;
NotifyPropertyChanged("CurrentLog");
}
}

并将其添加到我的OutputHandlermethod:中

CurrentLog = line;

并在我的XAML:中的ListViewSelectedItemproperty中使用它

<ListView Name="listViewResults"
ItemsSource="{Binding Results}"
SelectedItem="{Binding CurrentLog}"/>

结果是,我仍然需要手动向下滚动。

ListView中选择一个项不会自动将其滚动到视图中,而且您不能仅在XAML中这样做,但有一种替代代码隐藏的方法。您可以编写自定义行为。行为是可以附加到XAML中的控件的可重定位组件。

为此,请安装Microsoft。Xaml。行为。WpfNuget包到您的项目中。然后创建一个从Behavior<ListView>派生的类型,如下所示。

public class ScrollIntoSelectedItemBehavior : Behavior<ListView>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.SelectionChanged += OnSelectionChanged;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.SelectionChanged -= OnSelectionChanged;
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItem = AssociatedObject.SelectedItem;
if (selectedItem != null)
AssociatedObject.ScrollIntoView(selectedItem);
}
}

当行为附加到ListView控件时,将调用OnAttach方法。然后,它会侦听选择更改,并滚动到当前选定的项目(如果有(。

行为的酷之处在于,它们不存在于代码背后,您可以在任何兼容的控件上重用它们。要将行为附加到ListView,请执行以下操作。

<ListView Name="listViewResults"
ItemsSource="{Binding Results}"
SelectedItem="{Binding CurrentLog}">
<b:Interaction.Behaviors>
<local:ScrollIntoSelectedItemBehavior/>
</b:Interaction.Behaviors>
</ListView>

Interaction类型的XML命名空间添加到XAML文件中。

xmlns:b="http://schemas.microsoft.com/xaml/behaviors"

就是这样。当你设置一个不同的CurrentLog项目时,它会自动滚动到视图中。


我还想指出您设计中的一个潜在问题。您的Results集合包含类型为string的项目。如果有重复的项目,您将遇到意外的行为。

如果将项目42设为"Test",并添加同样拼写为"Test"的项目102,则列表将滚动到项目42,因为两个项目相等并且列表中的第一个项目获胜。为了解决这个问题,您必须创建一个自定义数据类型作为实际string的包装器,例如:

public MyDataItem
{
public string Log { get; }
public MyDataItem(string log)
{
Log = log;
}
// ...
}

这将起作用,因为将比较引用而不是字符串,并且它们是唯一的。

最新更新