同时滚动两个列表框 ( Windows Form )

Scrolling two listboxes ( Windows Form ) at same time

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

我用谷歌搜索了一些,我找到了这个 class 但它似乎不起作用:

 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;
        }

这对 copy/paste code from article and don't even bother to read everything about the code and user reviews. You are not the first one who get stuck in this place....because one user already commented the problem

来说是非常糟糕的做法

所以您可能错过的是订阅事件。有 2 个选项可以做到这一点:

  1. 在设计器中 window select 第一个列表框。然后在属性 window select 事件选项卡 (1.) 中查找 OnVerticalScroll 事件。当您找到它时,单击下拉按钮 (2.)。该列表应至少包含 2 个选项 syncListView1_OnVerticalScroll 和 syncListView1_OnVerticalScroll。所以selectsyncListView1_OnVerticalScroll。对第二个列表框做同样的事情,但是 select syncListView1_OnVerticalScrol2

  1. 在有列表框的表单中打开代码视图。应该有构造函数,其中调用了 InitializeComponent() 方法。在该方法之后添加以下代码行。

    syncListView1.OnVerticalScroll += 这个.syncListView1_OnVerticalScroll; syncListView2.OnVerticalScroll += 这个。syncListView2_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;
    }

您不需要派生 class SyncListBox

只需为 windows 表单 InitializeComponent() 或 windows 表单构造函数

中的两个列表框附加事件处理程序
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 ListBoxes,只需将它们传递到 Form 的 Load() 事件中的 SyncListBoxes 的构造函数中。这将处理垂直滚动、鼠标滚轮滚动,以及当 ListBoxes 因键盘输入(通过 SelectedIndexChanged 事件)而滚动时:

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;
            }
        }

    }

}