我有一个列表框,其中添加了各种项目。当一个新项目被添加到列表框中时,我需要将该项目滚动到视图中(基本上滚动到底部)。
我已尝试过How can I have a ListBox auto-scroll when a new item is added?以及this blog post
的解决方案然而,由于我的列表框包含可变高度项,因此两种解决方案均无效。如果我破解我的列表框项目模板而不是固定高度,那么它似乎工作。以下是我的一个项目模板示例:
<DataTemplate x:Key="StatusMessageTemplate">
<Grid Grid.Column="1" VerticalAlignment="top" Margin="0,5,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Path=MessageText}" HorizontalAlignment="Left" Grid.Row="0" Grid.Column="0" FontWeight="Bold" Foreground="{DynamicResource LightTextColorBrush}"/>
<TextBlock Text="{Binding Path=created_at, StringFormat=t}" Style="{StaticResource Timestamp}" TextWrapping="Wrap" HorizontalAlignment="Right" Grid.Row="0" Grid.Column="1"/>
</Grid>
</DataTemplate>
如何将新项目滚动到视图中,无论其高度如何?
答案 0 :(得分:2)
我需要将该项目滚动到视图中(基本上滚动到底部)。
当Listbox具有可变高度项时,ScrollIntoView的行为很奇怪。
如果唯一目的是滚动到底部,您可以直接访问Scrollviewer并滚动到最大可能的偏移量,如下所示。
var scrollViewer = GetDescendantByType(ListBoxChats, typeof(ScrollViewer)) as ScrollViewer;
scrollViewer.ScrollToVerticalOffset(Double.MaxValue);
public static Visual GetDescendantByType(Visual element, Type type)
{
if (element == null)
{
return null;
}
if (element.GetType() == type)
{
return element;
}
Visual foundElement = null;
if (element is FrameworkElement)
{
(element as FrameworkElement).ApplyTemplate();
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
foundElement = GetDescendantByType(visual, type);
if (foundElement != null)
{
break;
}
}
return foundElement;
}
GetDescendantByType是一个由punker76 @ another SO post编写的辅助函数
答案 1 :(得分:1)
我想我发现了这个问题。在显示之前不会计算可变高度项目。所以我添加一个计时器来调用ScrollIntoView函数。但即使这样也不行,所以我使用VisualTreeHelper查找ScrollViewer对象并强制它到特定行。这是代码。
System.Windows.Threading.DispatcherTimer dTimer = new System.Windows.Threading.DispatcherTimer();
dTimer.Interval = new TimeSpan(0, 0, 0, 0, 200); // 200 Milliseconds
dTimer.Tick += new EventHandler(
(seder, ea) =>
{
//Verses.ScrollIntoView(Verses.Items[itemIndex]);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(Verses); i++)
{
DependencyObject depObj = VisualTreeHelper.GetChild(Verses, i);
if (depObj is ScrollViewer)
{
ScrollViewer sv = depObj as ScrollViewer;
sv.ScrollToVerticalOffset(itemIndex); // Zero based index
break;
}
}
dTimer.Stop();
});
dTimer.Start();