滚动ListView到项目顶部意外调用了SourceChanged

本文关键字:调用 SourceChanged 意外 顶部 ListView 项目 滚动 | 更新日期: 2023-09-27 18:25:28

我已经设置了一个wpf用户控制项目,该项目与wpf Apps With the Model View ViewModel Design Pattern文章类似(大部分)。基本上,我有一个带标题的内容控件,其中包含一个选项卡控件。第一个选项卡包含搜索结果,通过单击搜索结果中的项目可以打开任何其他选项卡,以查看该项目的更详细视图。

我的主要问题是,每当有人键入搜索条件并运行搜索命令时,我都会重复使用搜索结果选项卡。当重新填充搜索结果集合时(如果用户向下滚动了列表),滚动查看器不会滚动到顶部。

最初,我重新填充搜索结果项集合的方式导致CollectionChanged事件触发。然后,我研究了使用附加的属性来允许滚动到顶部,看起来替换整个集合是可行的(因为ItemsControl没有实现ICollectionNotifyChanged接口)。

所以我做出了改变,一切看起来都很好。运行新的搜索替换了搜索结果项集合,该集合激发了附加的属性并将列表视图滚动回顶部。但是,我现在遇到了一个问题,每当我移动到另一个选项卡以查看项目的详细视图时,<strong]就会触发附加的属性,并将第一个选项卡上的搜索结果滚动到顶部>。我不知道如何解决这种情况。

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)
    {
        var itemsControl = dpo as ItemsControl;
        if (itemsControl == null) return;
        DependencyPropertyDescriptor dependencyPropertyDescriptor =
            DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, typeof (ItemsControl));
        if (dependencyPropertyDescriptor == null) return;
        if ((bool) e.NewValue)
        {
            dependencyPropertyDescriptor.AddValueChanged(itemsControl, ItemsSourceChanged);
        }
        else
        {
            dependencyPropertyDescriptor.RemoveValueChanged(itemsControl, ItemsSourceChanged);
        }
    }
    private static void ItemsSourceChanged(object sender, EventArgs e)
    {
        var itemsControl = sender as ItemsControl;
        EventHandler eventHandler = null;
        eventHandler = delegate
            {
                if (itemsControl != null &&
                    itemsControl.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
                {
                    var scrollViewer = VisualTreeHelpers.FindChild<ScrollViewer>(itemsControl);
                    scrollViewer.ScrollToTop();
                    itemsControl.ItemContainerGenerator.StatusChanged -= eventHandler;
                }
            };
        if (itemsControl != null) itemsControl.ItemContainerGenerator.StatusChanged += eventHandler;
    }
}

我已经将此属性附加到搜索结果用户控件上,如下所示:

<ListView ...some properties left out for brevity...
              DataContext="{StaticResource SearchResultsViewSource}"
              IsSynchronizedWithCurrentItem="True"
              ItemsSource="{Binding}"
              SelectionMode="Single"
              behaviours:ScrollToTopBehavior.ScrollToTop="True">
...etc...

搜索结果控件位于另一个使用标题内容控件的用户控件中(如果需要,我将提供详细信息)。

滚动ListView到项目顶部意外调用了SourceChanged

这是一个破解,虽然不能解决真正的问题,但可以解决症状
您可以分离您在CCD_ 1事件上的行为,因此,当您启动或转到"搜索结果"选项卡时,会附加行为/属性,而当您转到其他选项卡时,则会分离/注销行为。

应该是这样的:

yourTab.SelecnionChanged+= new TabControlCancelEventHandler(tabControl_Selecting);
void tabControl_SelecnionChange(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    var current = (sender as TabControl).SelectedValue;
    //check if current is search tab then
    {
      ScrollToTopBehavior.SetScrollToTop(yourList,true);
    }
    else
    {
      ScrollToTopBehavior.SetScrollToTop(yourList,false);
    }
}