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

时间:2015-01-14 15:05:05

标签: c# winforms

基本上我在Form上有两个列表框syncListView1和syncListView2(windows表单应用程序)我试图让他们的滚动条同步

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

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

4 个答案:

答案 0 :(得分:1)

这对于copy/paste code from article来说真是不好的做法,甚至懒得阅读有关代码和用户评论的所有内容。你并不是第一个被困在这个地方的人....因为one user already commented the problem

所以你可能错过的是订阅活动。有两种选择:

  1. 在设计器窗口中选择第一个列表框。然后在属性窗口中选择事件选项卡(1.)并查找OnVerticalScroll事件。当你找到它时点击下拉按钮(2.)。该列表应包含至少2个选项syncListView1_OnVerticalScroll和syncListView1_OnVerticalScroll。所以选择syncListView1_OnVerticalScroll。使用第二个列表框执行相同操作,但选择syncListView1_OnVerticalScrol2
  2. enter image description here

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

      syncListView1.OnVerticalScroll + = this.syncListView1_OnVerticalScroll; syncListView2.OnVerticalScroll + = this.syncListView2_OnVerticalScroll;

答案 1 :(得分:1)

您不需要派生类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;

答案 2 :(得分:0)

另一个例子......这个让你保持原始.Net ListBox到位,只需将它们传递给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;
            }
        }

    }

}

答案 3 :(得分:-1)

将列表框类型更改为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;
    }