WPF,ListBox逐项滚动到基于像素的滚动 [英] WPF, ListBox item-by-item scrolling to pixel based scrolling

查看:106
本文介绍了WPF,ListBox逐项滚动到基于像素的滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我插入listboxItem时,我正在使用以下代码修复屏幕.

I'm using below code for fix my screen when i insert listboxItem.

public partial class KeepItemsInViewListBox : ListBox
    {
        private ScrollViewer ScrollViewer { get; set; }

        #region Overrides of FrameworkElement

        /// <inheritdoc />
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (TryFindVisualChildElement(this, out ScrollViewer scrollViewer))
            {
                this.ScrollViewer = scrollViewer;
            }
        }

        #endregion

        #region Overrides of ListView

        /// <inheritdoc />
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);

            if (this.ScrollViewer == null)
            {
                return;
            }

            double verticalOffset;
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add when e.NewItems != null:
                    // Check if insert or add
                    verticalOffset = e.NewStartingIndex < this.ScrollViewer.VerticalOffset
                      ? this.ScrollViewer.VerticalOffset + e.NewItems.Count
                      : this.ScrollViewer.VerticalOffset;
                    break;
                case NotifyCollectionChangedAction.Remove when e.OldItems != null:
                    verticalOffset = this.ScrollViewer.VerticalOffset - e.OldItems.Count;
                    break;
                default:
                    verticalOffset = this.ScrollViewer.VerticalOffset;
                    break;
            }

            this.ScrollViewer?.ScrollToVerticalOffset(verticalOffset);
        }


        #endregion

        public bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild childElement)
          where TChild : FrameworkElement
        {
            childElement = null;
            if (parent == null)
            {
                return false;
            }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(parent, i);
                if (child is TChild resultElement)
                {
                    childElement = resultElement;
                    return true;
                }

                if (TryFindVisualChildElement(child, out childElement))
                {
                    return true;
                }
            }

            return false;
        }
    }

该类使我的列表框滚动到逐项显示.

that class makes my listbox's scroll to item-by-item.

请参见下图.

在上层类(KeepItemsInViewListBox)之前,我的滚动条件是Pixel.但是使用该代码后,我的滚动条件发生了变化.

before upper Class(KeepItemsInViewListBox), my scrolling condition is Pixel. but after using that code my scrolling condition is changed.

因为我所有的 listboxitem 的大小都不同,我在xaml中添加了 VirtualizingPanel.ScrollUnit ="Pixel" ScrollViewer.CanContentScroll ="False" ,或 ScrollViewer.CanContentScroll = false; 在.cs文件中然后我的屏幕也移动了...

because all of my listboxitem's size is diffrent, I added VirtualizingPanel.ScrollUnit="Pixel" or ScrollViewer.CanContentScroll = "False" in xaml, or ScrollViewer.CanContentScroll = false; in .cs file then my screen is also move...

推荐答案

首先要感谢Mr.Code

First thanks to Mr.Code

我修改了Code先生的班级,但是我的Code并不完美.

I modify Mr.Code's class, but my Code is not a perfect.

public class KeepItemsInViewListBox : ListBox
    {
        private ScrollViewer ScrollViewer { get; set; }

        private void ScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {


            if (insertCheck)
            {
                ScrollViewer.ScrollToVerticalOffset(ScrollViewer.VerticalOffset + e.ExtentHeightChange);
                insertCheck = false;
            }
        }

        #region Overrides of FrameworkElement

        /// <inheritdoc />
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            if (TryFindVisualChildElement(this, out ScrollViewer scrollViewer))
            {
                this.ScrollViewer = scrollViewer;
                ScrollViewer.ScrollChanged += ScrollViewer_ScrollChanged;
            }
        }

        #endregion
        private bool insertCheck = false;
        #region Overrides of ListView

        /// <inheritdoc />
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Add when e.NewItems != null:
                    bool isInsert = this.ScrollViewer.CanContentScroll
                      ? e.NewStartingIndex < this.ScrollViewer.VerticalOffset
                      : e.NewStartingIndex + 1 != this.Items.Count - 1;

                    if (!isInsert)
                    {
                        return;
                    }
                    insertCheck = isInsert;
                    break;
            }
        }
        #endregion

        public bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild childElement)
          where TChild : FrameworkElement
        {
            childElement = null;
            if (parent == null)
            {
                return false;
            }

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(parent, i);
                if (child is TChild resultElement)
                {
                    childElement = resultElement;
                    return true;
                }

                if (TryFindVisualChildElement(child, out childElement))
                {
                    return true;
                }
            }

            return false;
        }
    }

我只是重新定义了"ScrollViewer_ScrollChanged"方法,然后将verticalOffset设置为更改的偏移值.

I just redefine "ScrollViewer_ScrollChanged" method and set verticalOffset to changed offset value.

它在我的测试项目中有效.但在我的真实项目中不起作用.然后,我使用ScrollViewer的ExtentHeight值.我检查了第一个ExtentHeight并保存了它.滚动后,我比较两个ExtentHeight并将差异设置为verticalOffset.

It works in my test Project. but in my real Project doesn't work. Then i use ScrollViewer's ExtentHeight value. I checked the first ExtentHeight and it was saved. After scrolling, I compare two of ExtentHeight and set the diffrence to verticalOffset.

但是它不能很好地工作

这篇关于WPF,ListBox逐项滚动到基于像素的滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆