列表框ScrollIntoView不适用于可变高度项目

时间:2013-08-02 08:28:25

标签: wpf

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

我已尝试过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>

如何将新项目滚动到视图中,无论其高度如何?

2 个答案:

答案 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();