1

我有一个列表框,其中添加了各种项目。当一个新项目添加到列表框时,我需要将该项目滚动到视图中(基本上滚动到底部)。

我已经尝试了添加新项目时如何让 ListBox 自动滚动的解决方案?也来自这篇博文

但是,这两种解决方案都不起作用,因为我的列表框包含可变高度项。如果我修改我的列表框项目模板以使其具有固定高度,那么它似乎可以工作。这是我的一个项目模板的示例:

<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>

无论它们的高度如何,如何使新项目滚动到视图中?

4

2 回答 2

2

我需要将该项目滚动到视图中(基本上滚动到底部)。

当列表框具有可变高度项时,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编写的辅助函数

于 2015-06-09T15:01:33.787 回答
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();
于 2013-09-19T17:44:27.623 回答