C#仿QQ设置界面导航

效果预览,选择左边标签,右边内容会自动滚动到适当位置

public class AnchorPanel
    {
        List<PanelMenu> lst = new List<PanelMenu>();

        Control MenuPan { get; set; }

        XtraScrollableControl XSControl;

        public AnchorPanel(Panel PanMenu, XtraScrollableControl xtraScrollableControl)
        {
            MenuPan = PanMenu;
            XSControl = xtraScrollableControl;
            XSControl.Scroll += XSControl_Scroll;
            XSControl.MouseWheel += XSControl_MouseWheel;
            XSControl.SizeChanged += XSControl_SizeChanged;
            XSControl.VerticalScroll.LargeChange = 20;
        }

        void XSControl_SizeChanged(object sender, EventArgs e)
        {
            if (LastAnchor != null && LastAnchorIniHeight < (sender as Control).Height)
            {
                LastAnchor.AnchorContainer.Height = (sender as Control).Height;
            }
        }


        #region 容器滚动条移动事件
        void XSControl_MouseWheel(object sender, MouseEventArgs e)
        {

            XSControl_Scroll(sender, null);

        }

        void XSControl_Scroll(object sender, XtraScrollEventArgs e)
        {
            CurrentLable = GetMenu((sender as XtraScrollableControl).VerticalScroll.Value);
        }
        #endregion

        #region 添加锚点

        PanelMenu LastAnchor;
        int LastAnchorIniHeight;

        /// <summary>
        /// 添加锚点
        /// </summary>
        /// <param name="col">默认为控件的Top,Height,Text属性</param>
        /// <param name="LastControl">是否是最后一一个锚点,为了保证最后一个锚点定位在顶部,需要动态设置最后一个锚点的高度,如果最后一个锚点区域高度小于容器高度,则设置其高度为容器高度</param>
        public void AddAnchor(Control col, bool LastControl)
        {
            AddAnchor(col, col.Text, LastControl);
        }
        /// <summary>
        /// 添加锚点
        /// </summary>
        /// <param name="col">默认为控件的Top,Height属性</param>
        /// <param name="Caption">如果Caption为空则取Col的Text属性</param>
        /// <param name="LastControl">是否是最后一一个锚点,为了保证最后一个锚点定位在顶部,需要动态设置最后一个锚点的高度,如果最后一个锚点区域高度小于容器高度,则设置其高度为容器高度</param>
        public void AddAnchor(Control col, string Caption, bool LastControl)
        {

            Label lbl = new Label()
            {
                AutoSize = false,
                Dock = System.Windows.Forms.DockStyle.Top,
                Location = new System.Drawing.Point(0, 0),
                /*lbl.Size = new System.Drawing.Size(219, 37);*/
                Height = 37,
                TabIndex = 0,
                Text = Caption,
                TextAlign = System.Drawing.ContentAlignment.MiddleRight,
                Tag = col.Top.ToString()
            };

            IniEventLable(lbl);
            if (LastControl)
            {
                LastAnchor = new PanelMenu(lbl, col);
                LastAnchorIniHeight = col.Height;
                lst.Add(LastAnchor);
            }
            else
                lst.Add(new PanelMenu(lbl, col));

            MenuPan.Controls.Add(lbl);
            MenuPan.Controls.SetChildIndex(lbl, 0);

        }


        #endregion

        /// <summary>
        /// 根据滚动条位置获得对应的锚点空间
        /// </summary>
        /// <param name="ScrollValue">滚动条的值</param>
        /// <returns></returns>
        public Label GetMenu(int ScrollValue)
        {
            Label lbl = null;
            foreach (PanelMenu menu in lst)
            {
                if (menu.Top <= ScrollValue && menu.Buttom > ScrollValue)
                    lbl = menu.Label;
            }
            if (lbl == null)
            {
                return null;
            }
            return lbl;
        }

        /// <summary>
        /// 初始化锚点的事件
        /// </summary>
        /// <param name="lbl"></param>
        void IniEventLable(Label lbl)
        {
            lbl.MouseEnter += lbl_MouseEnter;
            lbl.MouseLeave += lbl_MouseLeave;

            lbl.MouseClick += lbl_MouseClick;
        }

        #region 锚点单击
        Label _CurrentLable;
        public Label CurrentLable
        {
            set
            {
                if (value == null) return;
                if (_CurrentLable == value) return;
                value.BackColor = Color.LightPink;
                if (_CurrentLable != null)
                    _CurrentLable.BackColor = Color.Transparent;
                _CurrentLable = value;
            }
            get { return _CurrentLable; } //{ return CurrentLable; }
        }

        /// <summary>
        /// 鼠标点击
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void lbl_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {

                CurrentLable = sender as Label;

                XSControl.VerticalScroll.Value = int.Parse((sender as Label).Tag.ToString()) - CurrentLable.Top;
            }
        }

        /// <summary>
        /// 设置鼠标进入时背景色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lbl_MouseEnter(object sender, EventArgs e)
        {
            if ((sender as Label) != CurrentLable)
                (sender as Label).BackColor = Color.FromArgb(0xFF, 0xFF, 0x99);
        }

        /// <summary>
        /// 鼠标移出,还原背景色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lbl_MouseLeave(object sender, EventArgs e)
        {
            if ((sender as Label) != CurrentLable)
                (sender as Label).BackColor = Color.Transparent;
        }
        #endregion
    }

    public class PanelMenu
    {
        public PanelMenu(Label label, Control anchorContainer)
        {
            Label = label;
            AnchorContainer = anchorContainer;
            Top = anchorContainer.Top;
        }

        public PanelMenu(Label label, int top, int height)
        {
            Label = label;
            Top = top;
            Height = height;
        }

        /// <summary>
        /// 锚点定位的容器对象,通常是Panel
        /// </summary>
        public Control AnchorContainer { get; set; }
        /// <summary>
        /// 锚点,Lable
        /// </summary>
        public Label Label { get; set; }


        public int Top
        {
            get;
            set;
        }
        private int _height;
        public int Height
        {
            get
            {
                if (AnchorContainer != null)
                    return AnchorContainer.Height;
                else
                    return _height;
            }
            set { _height = value; }
        }

        public int Buttom { get { return Top + Height; } }
    }

PS:界面新建一个panel1,用于存放左边的导航列表,右边拖一个dev控件:xtraScrollableControl1
在Load里面新增如下代码
使用:

AnchorPanel APanel;
       private void Form3_Load(object sender, EventArgs e)
       {
           APanel = new AnchorPanel(panel1, xtraScrollableControl1);

           labelControl1.Text = groupControl6.Height.ToString();
           if (groupControl6.Height < xtraScrollableControl1.Height)
               groupControl6.Height = xtraScrollableControl1.Height;
           panel1.Controls.Clear();

           APanel.AddAnchor(groupControl1, false);
           APanel.AddAnchor(groupControl2, false);
           APanel.AddAnchor(groupControl3, false);
           APanel.AddAnchor(groupControl4, false);
           APanel.AddAnchor(groupControl5, false);
           APanel.AddAnchor(groupControl6, true);
            
            
            
            
           

           APanel.CurrentLable = APanel.GetMenu(0);
            
            
            
            
            
       }

Demo下载地址:https://github.com/GarsonZhang/JumpPanel

慎于行,敏于思!GGGGGG
原文地址:https://www.cnblogs.com/GarsonZhang/p/4062625.html