C# 同时滚动两个列表框(Windows窗体)

C# 同时滚动两个列表框(Windows窗体),c#,winforms,C#,Winforms,基本上,我在窗体(windows窗体应用程序)上有两个列表框syncListView1和syncListView2,我试图使它们的滚动条同步 我在谷歌上搜索了一些,发现了这个类,但它似乎不起作用: class SyncListBox : System.Windows.Forms.ListBox { [Category("Action")] private const int WM_HSCROLL = 0x114; private cons

基本上,我在窗体(windows窗体应用程序)上有两个列表框syncListView1和syncListView2,我试图使它们的滚动条同步

我在谷歌上搜索了一些,发现了这个类,但它似乎不起作用:

 class SyncListBox : System.Windows.Forms.ListBox
    {
        [Category("Action")]
        private const int WM_HSCROLL = 0x114;
        private const int WM_VSCROLL = 0x115;
        public event ScrollEventHandler OnHorizontalScroll;
        public event ScrollEventHandler OnVerticalScroll;

        private const int SB_LINEUP = 0;
        private const int SB_LINELEFT = 0;
        private const int SB_LINEDOWN = 1;
        private const int SB_LINERIGHT = 1;
        private const int SB_PAGEUP = 2;
        private const int SB_PAGELEFT = 2;
        private const int SB_PAGEDOWN = 3;
        private const int SB_PAGERIGHT = 3;
        private const int SB_THUMBPOSITION = 4;
        private const int SB_THUMBTRACK = 5;
        private const int SB_PAGETOP = 6;
        private const int SB_LEFT = 6;
        private const int SB_PAGEBOTTOM = 7;
        private const int SB_RIGHT = 7;
        private const int SB_ENDSCROLL = 8;
        private const int SIF_TRACKPOS = 0x10;
        private const int SIF_RANGE = 0x1;
        private const int SIF_POS = 0x4;
        private const int SIF_PAGE = 0x2;
        private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;
        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetScrollInfo(
        IntPtr hWnd, int n, ref ScrollInfoStruct lpScrollInfo);

        private struct ScrollInfoStruct
        {
            public int cbSize;
            public int fMask;
            public int nMin;
            public int nMax;
            public int nPage;
            public int nPos;
            public int nTrackPos;
        }
        protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            if (msg.Msg == WM_HSCROLL)
            {
                if (OnHorizontalScroll != null)
                {
                    ScrollInfoStruct si = new ScrollInfoStruct();
                    si.fMask = SIF_ALL;
                    si.cbSize = Marshal.SizeOf(si);
                    GetScrollInfo(msg.HWnd, 0, ref si);
                    if (msg.WParam.ToInt32() == SB_ENDSCROLL)
                    {
                        ScrollEventArgs sargs = new ScrollEventArgs(
                        ScrollEventType.EndScroll,
                        si.nPos);
                        OnHorizontalScroll(this, sargs);
                    }
                }
            }
            if (msg.Msg == WM_VSCROLL)
            {
                if (OnVerticalScroll != null)
                {
                    ScrollInfoStruct si = new ScrollInfoStruct();
                    si.fMask = SIF_ALL;
                    si.cbSize = Marshal.SizeOf(si);
                    GetScrollInfo(msg.HWnd, 0, ref si);
                    if (msg.WParam.ToInt32() == SB_ENDSCROLL)
                    {
                        ScrollEventArgs sargs = new ScrollEventArgs(
                        ScrollEventType.EndScroll,
                        si.nPos);
                        OnVerticalScroll(this, sargs);
                    }
                }
            }
            base.WndProc(ref msg);
        }

        private void InitializeComponent()
        {
            this.SuspendLayout();
            // 
            // scrolled
            // 
            this.Size = new System.Drawing.Size(120, 95);
            this.ResumeLayout(false);
        }
    }
在代码背后:

private void syncListView2_OnVerticalScroll(object sender, ScrollEventArgs e)
        {
            syncListView1.TopIndex = syncListView2.TopIndex;
        }

        private void syncListView1_OnVerticalScroll(object sender, ScrollEventArgs e)
        {
            syncListView2.TopIndex = syncListView1.TopIndex;
        }

这是一种非常糟糕的做法,甚至不用费心去阅读关于代码和用户评论的所有内容。你不是第一个被困在这里的人…因为

所以你可能错过了订阅活动。有两个选项可供选择:

  • 在设计器窗口中,选择第一个列表框。然后在属性窗口中选择事件选项卡(1)并查找OnVerticalScroll事件。找到后,单击下拉按钮(2)。列表应至少包含两个选项syncListView1\u OnVerticalScroll和syncListView1\u OnVerticalScroll。因此,选择垂直滚动的syncListView1。对第二个列表框执行相同的操作,但选择垂直Scrol2上的同步列表视图
  • 在表单中,您可以在代码视图中打开列表框。应该有一个构造函数,其中调用了
    InitializeComponent()
    方法。在该方法之后添加以下代码行

    syncListView1.OnVerticalScroll+=this.syncListView1\u OnVerticalScroll; syncListView2.OnVerticalScroll+=this.syncListView2\u OnVerticalScroll


  • 将列表框类型更改为SyncListBox并附加到OnVerticalScroll事件

        //Omitted for brevity
         private SyncListBox listBox1;
         private SyncListBox listBox2;
    
        //Omitted for brevity
    
         this.listBox1 = new WindowsFormsApplication1.SyncListBox();
         this.listBox2 = new WindowsFormsApplication1.SyncListBox();
    
        //Omitted for brevity
        listBox1.OnVerticalScroll += listBox1_OnVerticalScroll;
        listBox2.OnVerticalScroll += listBox2_OnVerticalScroll;
    
        //Event handlers
        void listBox2_OnVerticalScroll(object sender, ScrollEventArgs e)
        {
           listBox1.TopIndex = listBox2.TopIndex;
        }
    
        void listBox1_OnVerticalScroll(object sender, ScrollEventArgs e)
        {
           listBox2.TopIndex = listBox1.TopIndex;
        }
    

    您不需要派生类SyncListBox

    只需按如下方式为windows窗体InitializeComponent()或windows窗体构造函数中的列表框附加EventHandler

    EventHandler handler = (s,e) =>{
                if (s == syncListView1)
                    syncListView2.TopIndex = syncListView1.TopIndex;
                if (s == syncListView2)
                    syncListView1.TopIndex = syncListView2.TopIndex;
            };
    
    this.syncListView1.MouseCaptureChanged += handler;
    this.syncListView2.MouseCaptureChanged += handler;
    this.syncListView1.SelectedIndexChanged += handler;
    this.syncListView2.SelectedIndexChanged += handler;
    

    另一个例子…这个例子可以让您保留原始的.Net列表框,只需在表单的Load()事件中将它们传递给SyncListBox的构造函数。这将处理垂直滚动、鼠标滚轮滚动以及当列表框由于键盘输入而滚动时(通过SelectedIndexChanged事件):


    你的问题是什么?它不起作用我需要帮助才能使它起作用他在问你如何能同时滚动两个列表框。
    它似乎不起作用
    请解释。你似乎没有向yout SyncListboxs订阅你的活动。。我到底应该在哪里插入此代码抱歉,我有点新,我更新了我的答案。添加了如何订阅事件的选项。嗯,listbox事件中没有此类事件,当我尝试第二个选项时,会出现错误系统。。不包含OnVerticalScroll的定义是否确实已删除窗体SyncListBox控件?在designer中选择它并查看属性窗口。在该行(图中的BTNADDREASE位置)中,您应该看到syncListView1***.SyncListBox。我猜是ListView。如果您看到not SyncListBox,请删除您的列表框。生成解决方案并尝试在工具箱窗口中查找SyncListBox。它应显示为齿轮状,并命名为SyncListBox。把它们写在你的表格里,然后按照我在回答中写的去做
    public partial class Form1 : Form
    {
    
        private SyncListBoxes _SyncListBoxes = null;
    
        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;
        }
    
        private void Form1_Load(object sender, EventArgs e)
        {
            this._SyncListBoxes = new SyncListBoxes(this.syncListView1, this.syncListView2);
        }
    
    }
    
    public class SyncListBoxes
    {
    
        private ListBox _LB1 = null;
        private ListBox _LB2 = null;
    
        private ListBoxScroll _ListBoxScroll1 = null;
        private ListBoxScroll _ListBoxScroll2 = null;
    
        public SyncListBoxes(ListBox LB1, ListBox LB2)
        {
            if (LB1 != null && LB1.IsHandleCreated && LB2 != null && LB2.IsHandleCreated && 
                LB1.Items.Count == LB2.Items.Count && LB1.Height == LB2.Height)
            {
                this._LB1 = LB1;
                this._ListBoxScroll1 = new ListBoxScroll(LB1);
                this._ListBoxScroll1.Scroll += _ListBoxScroll1_VerticalScroll;
    
                this._LB2 = LB2;
                this._ListBoxScroll2 = new ListBoxScroll(LB2);
                this._ListBoxScroll2.Scroll += _ListBoxScroll2_VerticalScroll;
    
                this._LB1.SelectedIndexChanged += _LB1_SelectedIndexChanged;
                this._LB2.SelectedIndexChanged += _LB2_SelectedIndexChanged;
            }
        }
    
        private void _LB1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this._LB2.TopIndex != this._LB1.TopIndex)
            {
                this._LB2.TopIndex = this._LB1.TopIndex;
            }
            if (this._LB2.SelectedIndex != this._LB1.SelectedIndex)
            {
                this._LB2.SelectedIndex = this._LB1.SelectedIndex;
            }
        }
    
        private void _LB2_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (this._LB1.TopIndex != this._LB2.TopIndex)
            {
                this._LB1.TopIndex = this._LB2.TopIndex;
            }
            if (this._LB1.SelectedIndex != this._LB2.SelectedIndex)
            {
                this._LB1.SelectedIndex = this._LB2.SelectedIndex;
            }
        }
    
        private void _ListBoxScroll1_VerticalScroll(ListBox LB)
        {
            if (this._LB2.TopIndex != this._LB1.TopIndex)
            {
                this._LB2.TopIndex = this._LB1.TopIndex;
            }
        }
    
        private void _ListBoxScroll2_VerticalScroll(ListBox LB)
        {
            if (this._LB1.TopIndex != this._LB2.TopIndex)
            {
                this._LB1.TopIndex = this._LB2.TopIndex;
            }
        }
    
        private class ListBoxScroll : NativeWindow
        {
    
            private ListBox _LB = null;
            private const int WM_VSCROLL = 0x115;
            private const int WM_MOUSEWHEEL = 0x20a;
    
            public event dlgListBoxScroll Scroll;
            public delegate void dlgListBoxScroll(ListBox LB);
    
            public ListBoxScroll(ListBox LB)
            {
                this._LB = LB;
                this.AssignHandle(LB.Handle);
            }
    
            protected override void WndProc(ref Message m)
            {
                base.WndProc(ref m);
                switch (m.Msg)
                {
                    case WM_VSCROLL:
                    case WM_MOUSEWHEEL:                        
                        if (this.Scroll != null)
                        {
                            this.Scroll(_LB);
                        }
                        break;
                }
            }
    
        }
    
    }