在TabControl TabItems之间切换时捕获和设置DataGrid滚动位置

时间:2017-09-10 04:26:19

标签: c# wpf datagrid tabcontrol scrollviewer

TabControl DataGrid位于每个TabItem内。它都是通过绑定填充的。我使用行详细信息扩展功能,因此将VirtualizingPanel ScrollUnit设置为Pixel,因此滚动更自然一些。

在TabItems之间切换时,行选择正确。但是,在DataGrid的ScrollViewer上设置垂直偏移,使其与您离开TabItem时的位置完全相同,无法正常工作。

目前它的工作方式是,我在DataGrid上有一个行为类。在Scrollviewer ScrollChangedEvent上,它会保存VerticalOffset。更改为新TabItem并更改回原始TabItem后,在DataGrid的DataContextChanged事件中,我将ScrollViewer的VerticalOffset设置为已保存的VerticalOffset。< / p>

public class DataGridBehaviors : Behavior<DataGrid>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.DataContextChanged += DataGrid_DataContextChanged;
        this.AssociatedObject.AddHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(DataGridScrollViewer_ScrollChanged));
    }

    protected override void OnDetaching()
    {
        Console.WriteLine("OnDetaching");
        this.AssociatedObject.RemoveHandler(ScrollViewer.ScrollChangedEvent, new ScrollChangedEventHandler(DataGridScrollViewer_ScrollChanged));
        this.AssociatedObject.DataContextChanged -= DataGrid_DataContextChanged;
        base.OnDetaching();
    }

    private void DataGrid_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        ModuleGeometry oldModuleGeometry = (ModuleGeometry)e.OldValue;
        ModuleGeometry newModuleGeometry = (ModuleGeometry)e.NewValue;
        ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(this.AssociatedObject);
        if (scrollViewer != null)
        {
            scrollViewer.ScrollToVerticalOffset(newModuleGeometry.VerticalScrollPosition);
        }
    }

    private void DataGridScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ModuleGeometry modGeom = (ModuleGeometry)this.AssociatedObject.DataContext;
        modGeom.VerticalScrollPosition = e.VerticalOffset;
    }

    private static 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;
    }
}

正在发生的事情是向下滚动并且顶部DataGridRow被部分显示(您只看到一半)。然后,当您在两个TabItem之间切换时,程序会正确设置VerticalOffset,但随后它会自动重置到部分显示的行的顶部(完全显示)。

切换之前。将VertcialOffset保存为4327.2 enter image description here 切换回原始TabItem设置VerticalOffset为4327.2后,由于某种原因,并以某种方式自动将VerticalOffset重置为4321.5,这是“以前”部分可见行的顶部 enter image description here

当你在VirtualizingPanel中加载了一个扩展行时,它变得更加怪异,跳跃更具戏剧性。

切换之前 enter image description here 切换回原始TabItem后 enter image description here

我希望滚动位置与我离开时的位置完全相同,我该如何实现?

1 个答案:

答案 0 :(得分:1)

最简单的方法可能是在切换标签时阻止TabControl卸载可视树。然后应保留每个标签的内容。

有关此内容的详情,请参阅以下链接。

How to stop Wpf Tabcontrol to unload Visual tree on Tab change

WPF - Elements inside DataTemplate property issue when no binding?