C# 清除项目时,WPF/MVVM树视图滚动条不会重置

C# 清除项目时,WPF/MVVM树视图滚动条不会重置,c#,wpf,treeview,scrollview,treeviewitem,C#,Wpf,Treeview,Scrollview,Treeviewitem,我正在使用WPF/MVVMTreeView来显示一些数据。由于可以有数千条记录,我使用页面显示它-每页100条,否则树将严重滞后和无响应。我已将分页功能封装到一个类中,该类由对象DuplicateFilesPageView表示,该对象公开绑定到TreeView的ObservableCollection对象-集合。要更改页面,请调用ObservableCollection.Clear(),然后为每个项添加(项),以重新填充集合 问题是,当项目被清除,然后添加新项目时,垂直滚动条不会改变其位置。如果

我正在使用WPF/MVVM
TreeView
来显示一些数据。由于可以有数千条记录,我使用页面显示它-每页100条,否则树将严重滞后和无响应。我已将分页功能封装到一个类中,该类由对象
DuplicateFilesPageView
表示,该对象公开绑定到
TreeView
ObservableCollection
对象-
集合。要更改页面,请调用
ObservableCollection.Clear()
,然后为每个项添加(项)
,以重新填充集合

问题是,当项目被清除,然后添加新项目时,垂直滚动条不会改变其位置。如果在中间滚动,如果没有足够的条目,它将滚动新视图到相同的位置或列表的末尾。 我需要它做的是当项目被重置时,垂直滚动条的位置也需要重置为0

我已尝试在我的ViewModel上引发PropertyChanged(name(DuplicateFilesPageView.Collection))事件
,但这没有帮助。 我也没有看到任何可以改变这种行为的属性

对于如何解决这个问题,我将不胜感激


//
///使文件可绑定的行为。
/// 
内部类BindableTreeViewSelectedItemBehavior:行为
{
#区域“SelectedItem”
public static readonly dependencProperty SelectedItemProperty=dependencProperty.Register(“SelectedItem”、typeof(object)、typeof(BindableTreeViewSelectedItemBehavior)、new FrameworkPropertyMetadata(null,frameworkpropertymetadaoptions.bindstwaway默认,OnSelectedItemChanged));
公共对象SelectedItem
{
get{返回this.GetValue(SelectEditeProperty);}
设置{this.SetValue(SelectedItemProperty,value);}
}
SelectedItemChanged上的私有静态无效(DependencyObject发件人、DependencyPropertyChangedEventArgs e)
{
如果(例如,NewValue是TreeViewItem项)
{
item.SetValue(TreeViewItem.IsSelectedProperty,true);
item.Focus();
返回;
}
if(发件人为BindableTreeViewSelectedItemBehavior行为)
{
var treeView=behavior.AssociatedObject;
if(treeView!=null)
{
item=GetTreeViewItem(树视图,例如NewValue);
如果(项!=null)
{
item.IsSelected=true;
item.Focus();
}
}
}
}
#端区
受保护的覆盖无效附加()
{
base.onatached();
this.AssociatedObject.SelectedItemChanged+=this.OnTreeViewSelectedItemChanged;
}
私有无效OnTreeViewSelectedItemChanged(对象发送方,RoutedPropertyChangedEventArgs e)
{
this.SelectedItem=e.NewValue;
}
附加时受保护的覆盖无效()
{
base.OnDetaching();
if(this.AssociatedObject!=null)
{
this.AssociatedObject.SelectedItemChanged-=this.OnTreeViewSelectedItemChanged;
}
}
#区域“GetBringIndexIntoView”
/// 
///GetBringIndexIntoView
/// 
/// 
///行动
私有静态操作GetBringIndexIntoView(面板项ShostPanel)
{
if(itemsHostPanel为虚拟化ZingStackPanel虚拟化ZingPanel)
{
var method=virtualizingPanel.GetType().GetMethod(“BringIndexIntoView”,BindingFlags.Instance | BindingFlags.NonPublic,Type.DefaultBinder,new[]{typeof(int)},null);
if(方法!=null)
{
返回i=>method.Invoke(virtualizengpanel,新对象[]{i});
}
}
返回null;
}
#端区
#区域“GetTreeViewItem”
/// 
///GetTreeViewItem
///递归搜索此子树中的项。
/// 
///父项控件。这可以是树视图或树视图项。
///要搜索的项目。
///树状网
私有静态TreeViewItem GetTreeViewItem(ItemsControl容器,对象项)
{
if(容器!=null)
{
if(container.DataContext==项)
{
将容器作为TreeViewItem返回;
}
//展开当前容器
if(容器是TreeViewItem&&!((TreeViewItem)容器).IsExpanded)
{
SetValue(treevieItem.IsExpandedProperty,true);
}
//尝试生成ItemsPresenter和ItemsPanel。
//通过调用ApplyTemplate
//虚拟化案例,即使项目已标记
//我们仍然需要执行此步骤,以便
//重新生成视觉效果,因为它们可能已被虚拟化。
container.ApplyTemplate();
var itemsPresenter=(itemsPresenter)container.Template.FindName(“ItemsHost”,container);
if(itemsPresenter!=null)
{
itemsPresenter.ApplyTemplate();
}
其他的
{
//树模板尚未命名ItemsPresenter,
//所以,带着后代去找孩子。
itemsPresenter=container.GetVisualDescendant();
if(itemsPresenter==null)
{
container.UpdateLayout();
itemsPresenter=container.GetVisualDescendant();
}
}
if(itemsPresenter!=null)
{
var itemsHostPanel=(面板)VisualTreeHelper.GetChild(itemsPresenter,0);
//
/// <summary>
///     Behavior that makes the <see cref="System.Windows.Controls.TreeView.SelectedItem" /> bindable.
/// </summary>
internal class BindableTreeViewSelectedItemBehavior : Behavior<TreeView>
{
    #region " SelectedItem "
    public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(BindableTreeViewSelectedItemBehavior), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemChanged));

    public object SelectedItem
    {
        get { return this.GetValue(SelectedItemProperty); }
        set { this.SetValue(SelectedItemProperty, value); }
    }

    private static void OnSelectedItemChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue is TreeViewItem item)
        {
            item.SetValue(TreeViewItem.IsSelectedProperty, true);
            item.Focus();
            return;
        }

        if (sender is BindableTreeViewSelectedItemBehavior behavior)
        {
            var treeView = behavior.AssociatedObject;
            if (treeView != null)
            {
                item = GetTreeViewItem(treeView, e.NewValue);
                if (item != null)
                {
                    item.IsSelected = true;
                    item.Focus();
                }
            }
        }
    }
    #endregion

    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectedItemChanged += this.OnTreeViewSelectedItemChanged;
    }

    private void OnTreeViewSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        this.SelectedItem = e.NewValue;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.SelectedItemChanged -= this.OnTreeViewSelectedItemChanged;
        }
    }

    #region " GetBringIndexIntoView "
    /// <summary>
    /// GetBringIndexIntoView
    /// </summary>
    /// <param name="itemsHostPanel"></param>
    /// <returns>Action<int></returns>
    private static Action<int> GetBringIndexIntoView(Panel itemsHostPanel)
    {
        if (itemsHostPanel is VirtualizingStackPanel virtualizingPanel)
        {
            var method = virtualizingPanel.GetType().GetMethod("BringIndexIntoView", BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder, new[] { typeof(int) }, null);
            if (method != null)
            {
                return i => method.Invoke(virtualizingPanel, new object[] { i });
            }
        }

        return null;
    }
    #endregion

    #region " GetTreeViewItem "
    /// <summary>
    /// GetTreeViewItem
    /// Recursively search for an item in this subtree.
    /// </summary>
    /// <param name="container">The parent ItemsControl. This can be a TreeView or a TreeViewItem.</param>
    /// <param name="item">The item to search for.</param>
    /// <returns>TreeViewItem</returns>
    private static TreeViewItem GetTreeViewItem(ItemsControl container, object item)
    {
        if (container != null)
        {
            if (container.DataContext == item)
            {
                return container as TreeViewItem;
            }

            // Expand the current container
            if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)
            {
                container.SetValue(TreeViewItem.IsExpandedProperty, true);
            }

            // Try to generate the ItemsPresenter and the ItemsPanel.
            // by calling ApplyTemplate.  Note that in the 
            // virtualizing case even if the item is marked 
            // expanded we still need to do this step in order to 
            // regenerate the visuals because they may have been virtualized away.
            container.ApplyTemplate();
            var itemsPresenter = (ItemsPresenter)container.Template.FindName("ItemsHost", container);
            if (itemsPresenter != null)
            {
                itemsPresenter.ApplyTemplate();
            }
            else
            {
                // The Tree template has not named the ItemsPresenter, 
                // so walk the descendents and find the child.
                itemsPresenter = container.GetVisualDescendant<ItemsPresenter>();
                if (itemsPresenter == null)
                {
                    container.UpdateLayout();
                    itemsPresenter = container.GetVisualDescendant<ItemsPresenter>();
                }
            }

            if (itemsPresenter != null)
            {
                var itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);

                // Ensure that the generator for this panel has been created.
#pragma warning disable 168
                var children = itemsHostPanel.Children;
#pragma warning restore 168

                var bringIndexIntoView = GetBringIndexIntoView(itemsHostPanel);
                for (int i = 0, count = container.Items.Count; i < count; i++)
                {
                    TreeViewItem subContainer;
                    if (bringIndexIntoView != null)
                    {
                        // Bring the item into view so 
                        // that the container will be generated.
                        bringIndexIntoView(i);
                        subContainer = (TreeViewItem)container.ItemContainerGenerator.ContainerFromIndex(i);
                    }
                    else
                    {
                        subContainer = (TreeViewItem)container.ItemContainerGenerator.ContainerFromIndex(i);

                        // Bring the item into view to maintain the 
                        // same behavior as with a virtualizing panel.
                        subContainer.BringIntoView();
                    }

                    if (subContainer == null)
                    {
                        continue;
                    }

                    // Search the next level for the object.
                    var resultContainer = GetTreeViewItem(subContainer, item);
                    if (resultContainer != null)
                    {
                        return resultContainer;
                    }

                    // The object is not under this TreeViewItem
                    // so collapse it.
                    subContainer.IsExpanded = false;
                }
            }
        }

        return null;
    }
    #endregion
}
<TreeView Grid.Column="1" Grid.Row="1" ItemsSource="{Binding MyTree}" MaxHeight="270" ScrollViewer.VerticalScrollBarVisibility="Auto" VirtualizingStackPanel.IsVirtualizing="True">
                <i:Interaction.Behaviors>
                    <h:BindableTreeViewSelectedItemBehavior SelectedItem="{Binding SelectedTV}"></h:BindableTreeViewSelectedItemBehavior>
                </i:Interaction.Behaviors>
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type wiz:TVTest}">
                        <Label Content="{Binding Name}"></Label>
                        <HierarchicalDataTemplate.ItemTemplate>
                            <HierarchicalDataTemplate ItemsSource="{Binding Children}" DataType="{x:Type wiz:TVTest}">
                                <Label Content="{Binding Name}"></Label>
                                <HierarchicalDataTemplate.ItemTemplate>
                                    <DataTemplate DataType="{x:Type wiz:TVTest}">
                                        <Label Content="{Binding Name}"></Label>
                                    </DataTemplate>
                                </HierarchicalDataTemplate.ItemTemplate>
                            </HierarchicalDataTemplate>
                        </HierarchicalDataTemplate.ItemTemplate>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
            </TreeView>
public static T GetVisualDescendant<T>(this DependencyObject visual) where T : DependencyObject
    {
        return (T)visual.GetVisualDescendants().FirstOrDefault(d => d is T);
    }

public static IEnumerable<DependencyObject> GetVisualDescendants(this DependencyObject visual)
    {
        if (visual == null)
        {
            yield break;
        }

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(visual, i);
            yield return child;

            if (VisualTreeHelper.GetChildrenCount(child) == 0)
            {
                continue;
            }

            foreach (DependencyObject subChild in GetVisualDescendants(child))
            {
                yield return subChild;
            }
        }
    }
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        GetScrollViewer(sender as UIElement).ScrollToTop();
    }

    public static ScrollViewer GetScrollViewer(UIElement element)
    {
        if (element == null) return null;

        ScrollViewer retour = null;
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element) && retour == null; i++)
        {
            if (VisualTreeHelper.GetChild(element, i) is ScrollViewer)
            {
                retour = (ScrollViewer)(VisualTreeHelper.GetChild(element, i));
            }
            else
            {
                retour = GetScrollViewer(VisualTreeHelper.GetChild(element, i) as UIElement);
            }
        }
        return retour;
    }