C# Windows窗体同时滚动多个列表框

C# Windows窗体同时滚动多个列表框,c#,.net,winforms,listbox,C#,.net,Winforms,Listbox,我正在使用WindowsForms,我有两个列表框。我可以分别成功滚动两个列表框,但我想“同步”滚动。因此,当我滚动ListBox1时,我想同时滚动ListBox2,选择ListBox2的相应字段,并将其与ListBox1对齐。 我已经查过了,还有很多其他的帖子 下面是它的外观: 以下是我努力实现的目标: 这似乎是一项复杂的任务。然而,在的帮助下,我设法找到了这个解决方案 您必须创建一个类似于listBox的新控件,该控件的事件已滚动,这可以使用此方法完成 在项目内部,右键单击项目节点并选择添

我正在使用WindowsForms,我有两个列表框。我可以分别成功滚动两个列表框,但我想“同步”滚动。因此,当我滚动
ListBox1
时,我想同时滚动
ListBox2
,选择
ListBox2
的相应字段,并将其与
ListBox1
对齐。 我已经查过了,还有很多其他的帖子

下面是它的外观:

以下是我努力实现的目标:


这似乎是一项复杂的任务。然而,在的帮助下,我设法找到了这个解决方案

您必须创建一个类似于
listBox
的新控件,该控件的事件
已滚动
,这可以使用此方法完成

在项目内部,右键单击项目节点并选择添加用户控件(Windows窗体),将其命名为ScrollingListBox.cs。它将与名为“ScrollingListBox.Designer.cs”的文件一起出现在解决方案资源管理器中,右键单击后一个文件并将其删除,然后选择“ScrollingListBox.cs”,右键单击它并选择“查看代码”,或按F7,然后用以下代码替换其内容:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Scroll
{
    public partial class ScrollingListBox : ListBox
    {

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        [Category("Action")]
        public event ScrollEventHandler Scrolled = null;

        private const int WM_VSCROLL = 0x115;
        private const int SB_ENDSCROLL = 0x8;
        private const int SIF_RANGE = 0x1;
        private const int SIF_PAGE = 0x2;
        private const int SIF_POS = 0x4;
        private const int SIF_TRACKPOS = 0x10;
        private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;

        private struct ScrollInfoStruct
        {
            public int cbSize;
            public int fMask;
            public int nMin;
            public int nMax;
            public int nPage;
            public int nPos;
            public int nTrackPos;
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetScrollInfo(IntPtr hWnd, int n, ref ScrollInfoStruct lpScrollInfo);

        protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            if (msg.Msg == WM_VSCROLL)
            {
                if (Scrolled != 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);
                        Scrolled(this, sargs);
                    }
                }
            }
            base.WndProc(ref msg);
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
                components.Dispose();
            base.Dispose(disposing);
        }
    }
}

还有这条线和类似的线,

this.listBox1 = new System.Windows.Forms.ListBox();
private System.Windows.Forms.ListBox listBox1;

现在,您可以使用此事件检测一个框中发生的滚动,并相应地修改另一个框,如下所示:

private void listBox1_Scrolled(object sender, ScrollEventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_Scrolled(object sender, ScrollEventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
private void listBox1_MouseHover(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseHover(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}

private void listBox1_MouseMove(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseMove(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
这可以通过单击滚动条的箭头或用鼠标抓图来滚动滚动条,但不适用于在框内使用鼠标滚轮。我尝试使用事件
mouseweel
来解决此问题,但不幸的是,它没有按预期工作,因此我找到的唯一选项是使用事件
MouseHover
MouseMove
来完成此操作,如下所示:

private void listBox1_Scrolled(object sender, ScrollEventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_Scrolled(object sender, ScrollEventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
private void listBox1_MouseHover(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseHover(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}

private void listBox1_MouseMove(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseMove(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
如果您在框的白色区域内的任何位置使用鼠标滚轮,这将起作用。不幸的是,如果您在滚动条上使用鼠标滚轮,这将不起作用

这可能足以解决您的问题,但如果您需要同时在两个框中选择相应索引的代码,请参阅:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{ 
    listBox2.SelectedIndex = listBox1.SelectedIndex;
}

private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{ 
    listBox1.SelectedIndex = listBox2.SelectedIndex;
}

这似乎是一项复杂的任务。然而,在的帮助下,我设法找到了这个解决方案

您必须创建一个类似于
listBox
的新控件,该控件的事件
已滚动
,这可以使用此方法完成

在项目内部,右键单击项目节点并选择添加用户控件(Windows窗体),将其命名为ScrollingListBox.cs。它将与名为“ScrollingListBox.Designer.cs”的文件一起出现在解决方案资源管理器中,右键单击后一个文件并将其删除,然后选择“ScrollingListBox.cs”,右键单击它并选择“查看代码”,或按F7,然后用以下代码替换其内容:

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Scroll
{
    public partial class ScrollingListBox : ListBox
    {

        /// <summary> 
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        [Category("Action")]
        public event ScrollEventHandler Scrolled = null;

        private const int WM_VSCROLL = 0x115;
        private const int SB_ENDSCROLL = 0x8;
        private const int SIF_RANGE = 0x1;
        private const int SIF_PAGE = 0x2;
        private const int SIF_POS = 0x4;
        private const int SIF_TRACKPOS = 0x10;
        private const int SIF_ALL = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_TRACKPOS;

        private struct ScrollInfoStruct
        {
            public int cbSize;
            public int fMask;
            public int nMin;
            public int nMax;
            public int nPage;
            public int nPos;
            public int nTrackPos;
        }

        [DllImport("user32.dll", SetLastError = true)]
        private static extern int GetScrollInfo(IntPtr hWnd, int n, ref ScrollInfoStruct lpScrollInfo);

        protected override void WndProc(ref System.Windows.Forms.Message msg)
        {
            if (msg.Msg == WM_VSCROLL)
            {
                if (Scrolled != 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);
                        Scrolled(this, sargs);
                    }
                }
            }
            base.WndProc(ref msg);
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
                components.Dispose();
            base.Dispose(disposing);
        }
    }
}

还有这条线和类似的线,

this.listBox1 = new System.Windows.Forms.ListBox();
private System.Windows.Forms.ListBox listBox1;

现在,您可以使用此事件检测一个框中发生的滚动,并相应地修改另一个框,如下所示:

private void listBox1_Scrolled(object sender, ScrollEventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_Scrolled(object sender, ScrollEventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
private void listBox1_MouseHover(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseHover(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}

private void listBox1_MouseMove(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseMove(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
这可以通过单击滚动条的箭头或用鼠标抓图来滚动滚动条,但不适用于在框内使用鼠标滚轮。我尝试使用事件
mouseweel
来解决此问题,但不幸的是,它没有按预期工作,因此我找到的唯一选项是使用事件
MouseHover
MouseMove
来完成此操作,如下所示:

private void listBox1_Scrolled(object sender, ScrollEventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_Scrolled(object sender, ScrollEventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
private void listBox1_MouseHover(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseHover(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}

private void listBox1_MouseMove(object sender, EventArgs e)
{
    listBox2.TopIndex = listBox1.TopIndex;
}

private void listBox2_MouseMove(object sender, EventArgs e)
{
    listBox1.TopIndex = listBox2.TopIndex;
}
如果您在框的白色区域内的任何位置使用鼠标滚轮,这将起作用。不幸的是,如果您在滚动条上使用鼠标滚轮,这将不起作用

这可能足以解决您的问题,但如果您需要同时在两个框中选择相应索引的代码,请参阅:

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{ 
    listBox2.SelectedIndex = listBox1.SelectedIndex;
}

private void listBox2_SelectedIndexChanged(object sender, EventArgs e)
{ 
    listBox1.SelectedIndex = listBox2.SelectedIndex;
}

好的,谢谢你们帮我。我使用了带有两列的
DataGridView
,正如@41686d6564所建议的那样,它就像一个符咒


好的,谢谢你们帮助我。我使用了带有两列的
DataGridView
,正如@41686d6564所建议的那样,它就像一个符咒


这是可行的,但为什么要重新发明轮子呢?改为使用带有两列的DataGridView。那么您检查了其他帖子,什么不起作用?您的问题的当前状态将与您所指的帖子重复。@41686d6564确实DataGridView可以工作,但这需要在项目中进行大量更改。我将检查并尝试实施它。能否请您也指导我关于如何同步两个列表框滚动的初始问题?@nilsK我的项目中缺少了他们所指的许多东西(例如syncListView1_OnVerticalScroll)。@很好奇,很抱歉,我现在没有时间编写和测试一些我认为没有用的代码。同样,不要试图重新发明轮子。使用DataGridView、ListView或任何可以包含列的控件,而不是试图模仿行为。这是可行的,但为什么要重新发明轮子呢?改为使用带有两列的DataGridView。那么您检查了其他帖子,什么不起作用?您的问题的当前状态将与您所指的帖子重复。@41686d6564确实DataGridView可以工作,但这需要在项目中进行大量更改。我将检查并尝试实施它。能否请您也指导我关于如何同步两个列表框滚动的初始问题?@nilsK我的项目中缺少了他们所指的许多东西(例如syncListView1_OnVerticalScroll)。@很好奇,很抱歉,我现在没有时间编写和测试一些我认为没有用的代码。再次强调,不要试图重新投资