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