WPF - 在ItemsSource更改时重置ListBox滚动位置

时间:2011-01-25 11:37:05

标签: wpf listbox scroll itemssource

我目前有一个ListBox,其ItemsSource集合绑定到我的viewmodel上的一个属性,类型为IEnumerable。当preoprty的引用发生更改时,ListBox会按预期更新,但是我有一个问题,如果我有大量项目并滚动到ListBox的底部,然后将引用更改为包含例如1项的另一个集合,ListBox视图为空,不显示滚动条。然后我必须用鼠标滚轮向上滚动列表框,直到看到1个项目。

因此,我认为我所追求的是,​​只要ItemsSource属性发生更改,就会将ListBox的滚动位置重置为顶部,这样无论收集的大小,都会显示一些内容。< / p>

5 个答案:

答案 0 :(得分:21)

我无法重现您的问题(对我来说,ListBox在更改ItemsSource时会滚动到新集合中的最后一项。无论如何,每次ListBox更改时,只需将ItemsSource滚动到顶部,您就可以使用一些代码。首先听取ItemsSourceProperty中的更改,然后在生成项目后将ListBox滚动到顶部

更新

做了一个附加的行为,这样做可以避免代码落后。它可以像这样使用

<ListBox ...
         behaviors:ScrollToTopBehavior.ScrollToTop="True"/>

ScrollToTopBehavior

public static class ScrollToTopBehavior 
{
    public static readonly DependencyProperty ScrollToTopProperty = 
        DependencyProperty.RegisterAttached 
        (
            "ScrollToTop", 
            typeof(bool),
            typeof(ScrollToTopBehavior),
            new UIPropertyMetadata(false, OnScrollToTopPropertyChanged) 
        );
    public static bool GetScrollToTop(DependencyObject obj) 
    {
        return (bool)obj.GetValue(ScrollToTopProperty); 
    }
    public static void SetScrollToTop(DependencyObject obj, bool value) 
    {
        obj.SetValue(ScrollToTopProperty, value); 
    }
    private static void OnScrollToTopPropertyChanged(DependencyObject dpo, 
                                                     DependencyPropertyChangedEventArgs e) 
    {
        ItemsControl itemsControl = dpo as ItemsControl;
        if (itemsControl != null) 
        {
            DependencyPropertyDescriptor dependencyPropertyDescriptor =
                    DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof(ItemsControl));
            if (dependencyPropertyDescriptor != null)
            {
                if ((bool)e.NewValue == true) 
                {
                    dependencyPropertyDescriptor.AddValueChanged(itemsControl, ItemsSourceChanged);
                }
                else 
                {
                    dependencyPropertyDescriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged);
                }
            } 
        } 
    }
    static void ItemsSourceChanged(object sender, EventArgs e)
    {
        ItemsControl itemsControl = sender as ItemsControl;
        EventHandler eventHandler = null;
        eventHandler = new EventHandler(delegate
        {
            if (itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            {
                ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(itemsControl) as ScrollViewer;
                scrollViewer.ScrollToTop();
                itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler;
            }
        });
        itemsControl.ItemContainerGenerator.StatusChanged += eventHandler;
    }
}

GetVisualChild的实现

private T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
    T child = default(T);
    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
        if (child != null)
        {
            break;
        }
    }
    return child;
}

答案 1 :(得分:7)

迟到的回答

一个简单的解决方案是为TargetUpdated事件添加事件处理程序,并在NotifyOnTargetUpdated=True绑定上设置ItemsSource

<ListBox x:Name="listBox" 
         ItemsSource="{Binding MySource, NotifyOnTargetUpdated=True}"
         TargetUpdated="ListBox_TargetUpdated"/>

并在事件处理程序中,滚动到顶部项目:

private void ListBox_TargetUpdated(object sender, DataTransferEventArgs e)
{
    if (listBox.Items.Count > 0)
    {
        listBox.ScrollIntoView(listBox.Items[0]);
    }
}

答案 2 :(得分:1)

试试这个:

if (listBox.Items.Count > 0) {
    listBox.ScrollIntoView(listBox.Items[0]); 
}

答案 3 :(得分:0)

改进了Fredrik Hedblad使用ObservableCollection的答案:

std::cout << 0 << " " << is_small<0>() << std::endl;

答案 4 :(得分:0)

格式化控件时,选择一系列单元格作为选择选项,然后在列表框中列出。您还可以选择一个单元格作为所选选项的链接,其中将显示一个数字,具体取决于列表中选择的位置。列表中的第一个为1,第二个为2等。代码非常简单: -

范围( “A1”)选择

选择= 1

将(“A1”)更改为您已链接的单元格 并将1更改为您想要选择的列表中的位置。

作为链接的单元格引用是双向的 - 如果更改选择,单元格中的数字会更改,如果更改单元格中的数字,则突出显示的选择会更改。