c#wpf - ListView.ScrollIntoView(LastItem)无法正常工作

时间:2017-05-31 11:35:42

标签: c# wpf listview event-handling scrollbar

和其他人一样,我有一个ListView(通过GridView中的绑定更新)。 我想在视图中保留最后插入的项目。所以我试过

LView.ScrollIntoView(LView.Items[LView.Items.Count - 1]);

这工作得很好。尽管第一项必须滚动到视图中的项目仅显示为整行的80%(取决于我定义整个ListView的高度,我差不多100%)。

真正的问题是未显示应滚动到视图中的以下项目。在Scrollbar本身也不明显,它不在底部。

Last Item is not shown

这是我的MainWindow的代码。

public partial class MainWindow : Window
{
    private InterfaceCtrl ICtrl;
    private ListView LView;
    public MainWindow()
    {
        InitializeComponent();

        this.ICtrl = new InterfaceCtrl();
        this.ICtrl.ProgressCollection.CollectionChanged += this.CollectionChanged;

        Grid MainGrid = new Grid();
        this.Content = MainGrid;

        GridView gv = new GridView();
        Binding StartTimeStampBinding = new Binding() { Path = new PropertyPath("StartTS"), Mode = BindingMode.OneWay, StringFormat = "dd.MM.yyyy - HH:mm:ss.fff" };
        GridViewColumn gvTCStartTS = new GridViewColumn() { Header = "Time", Width = 150.00, DisplayMemberBinding = StartTimeStampBinding };
        gv.Columns.Add(gvTCStartTS);

        LView = new ListView() { Height = 192, Width = 250, HorizontalAlignment = HorizontalAlignment.Left, VerticalAlignment = VerticalAlignment.Top, View = gv, ItemsSource = this.ICtrl.ProgressCollection };

        MainGrid.Children.Add(LView);

        ICtrl.StartMyThread();
    }

    private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Action(delegate ()
        {
            if (LView != null && LView.Items.Count > 0)
            {
                LView.UpdateLayout();
                //LView.ScrollIntoView(LView.Items[LView.Items.Count - 1]);

                LView.SelectedIndex = LView.Items.Count;
                LView.ScrollIntoView(LView.SelectedItem);                    
            }

        }));
    }

}

谢谢。

编辑: 这似乎是一个计时问题,虽然所有想要的数据都在LView的正确时间我尝试了一个与文本框绑定到时间戳的解决方法。

        TextBox tb = new TextBox(); // { Width = 250, Height = 28, Margin= new Thickness(10,100,1,0)};
        tb.SetBinding( TextBox.TextProperty , new Binding("LastMsgTimestamp") { Source = this.ICtrl, Mode = BindingMode.OneWay, StringFormat = "dd.MM.yyyy - HH:mm:ss.fff" });

        tb.TextChanged += this.UpdateScrollbar;
        tb.Visibility = Visibility.Hidden;

在我看来,在绑定到LView和ObservableCollection的触发事件中存在时间问题。这还包括ObservableCollection的PropertyChanged。

我在LView中直接尝试了TargetUpdated和SoruceUpdated事件,但这些事件根本没有出现。

2 个答案:

答案 0 :(得分:1)

您可以尝试调用ScrollToBottom()内部ScrollToVerticalOffset()元素的任意ListViewScrollViewer方法:

private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new System.Action(delegate ()
    {
        if (LView != null && LView.Items.Count > 0)
        {
            LView.UpdateLayout();
            ScrollViewer sv = GetChildOfType<ScrollViewer>(LView);
            if (sv != null)
                sv.ScrollToBottom();

            LView.SelectedIndex = LView.Items.Count;
            LView.ScrollIntoView(LView.SelectedItem);
        }

    }));
}

private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null)
        return null;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        var child = VisualTreeHelper.GetChild(depObj, i);

        var result = (child as T) ?? GetChildOfType<T>(child);
        if (result != null)
            return result;
    }
    return null;
}

答案 1 :(得分:1)

我做了以下样本。您可以尝试在内部ScrollViewer中调用ScrollToBottom,因为@ mm8指出。然而,当看到答案时,我已经在制作我的样本,所以这里是:

代码隐藏

using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;


namespace ListViewScroll
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<string> Names { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            Names = new ObservableCollection<string>();
            ListView.ItemsSource = Names;
        }

        private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
        {
            Names.Add("Some Name" + ++someInt);
            // Get the border of the listview (first child of a listview)
            var border = VisualTreeHelper.GetChild(ListView, 0) as Decorator;

            // Get scrollviewer
            var scrollViewer = border.Child as ScrollViewer;
            scrollViewer.ScrollToBottom();
        }

        private static int someInt;
    }
}

XAML

<Window x:Class="ListViewScroll.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>

        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <ListView Grid.Row="0" Name="ListView"/>

        <Button Content="Add" FontSize="20" Grid.Row="1"
                Click="ButtonBase_OnClick"/>
    </Grid>
</Window>

在这种情况下,我正在处理按钮点击事件中的滚动,但您可以根据自己的要求进行更改

enter image description here

它有效,我已经测试过了。

希望这有帮助