c# - 如何使用 slider 在两个 TreeView 中同步滚动

标签 c# winforms treeview

我正在使用 Visual Studio 2010 (C#) 和 Windows 窗体应用程序。

我有两个并排的 TreeView ,我已经想出了如何使用滚动条上的向上/向下按钮同步滚动,但是当我使用 slider 时它不会移动另一个 TreeView 。我采用了一个有效的 ListView 示例,但相同的代码不适用于 TreeView 。

到目前为止,我的主要形式是:

    [DllImport("User32.dll")]
    public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);

    private void myListBox1_Scroll(ref Message m)
    {
        SendMessage(myListBox2.Handle, (uint)m.Msg, (uint)m.WParam, (uint)m.LParam);
    }

我创建了一个控件:

public partial class MyTreeView : TreeView
{
    public MyTreeView()
    {
        InitializeComponent();
    }

    public event ScrollEventHandler Scroll;
    public delegate void ScrollEventHandler(ref Message m);


    private const int WM_VSCROLL = 0x115;

    protected override void WndProc(ref System.Windows.Forms.Message m)
    {
        if (m.Msg == WM_VSCROLL)
            if (Scroll != null)
            {
                Scroll(ref m);
            }

        base.WndProc(ref m);
    }

}

我在表格中添加了两个。

我可以使用相同的代码让 listivew 控制 TreeView ,如果您拖动 slider ,它会起作用,但反过来它只适用于上下按钮。

最佳答案

与其使用 SendMessage 并将您的 DLL 标记为不安全,不如使用 user32.dll 中的 GetScrollPosSetScrollPos 函数。

我已将代码封装到您的 MyTreeView 类中,因此封装得很好。

您只需像这样调用AddLinkedTreeView 方法:

treeView1.AddLinkedTreeView(treeView2);

这是 MyTreeView 类的源代码。

public partial class MyTreeView : TreeView
{
    public MyTreeView() : base()
    {
    }

    private List<MyTreeView> linkedTreeViews = new List<MyTreeView>();

    /// <summary>
    /// Links the specified tree view to this tree view.  Whenever either treeview
    /// scrolls, the other will scroll too.
    /// </summary>
    /// <param name="treeView">The TreeView to link.</param>
    public void AddLinkedTreeView(MyTreeView treeView)
    {
        if (treeView == this)
            throw new ArgumentException("Cannot link a TreeView to itself!", "treeView");

        if (!linkedTreeViews.Contains(treeView))
        {
            //add the treeview to our list of linked treeviews
            linkedTreeViews.Add(treeView);
            //add this to the treeview's list of linked treeviews
            treeView.AddLinkedTreeView(this);

            //make sure the TreeView is linked to all of the other TreeViews that this TreeView is linked to
            for (int i = 0; i < linkedTreeViews.Count; i++)
            {
                //get the linked treeview
                var linkedTreeView = linkedTreeViews[i];
                //link the treeviews together
                if (linkedTreeView != treeView)
                    linkedTreeView.AddLinkedTreeView(treeView);
            }
        }
    }

    /// <summary>
    /// Sets the destination's scroll positions to that of the source.
    /// </summary>
    /// <param name="source">The source of the scroll positions.</param>
    /// <param name="dest">The destinations to set the scroll positions for.</param>
    private void SetScrollPositions(MyTreeView source, MyTreeView dest)
    {
        //get the scroll positions of the source
        int horizontal = User32.GetScrollPos(source.Handle, Orientation.Horizontal);
        int vertical = User32.GetScrollPos(source.Handle, Orientation.Vertical);
        //set the scroll positions of the destination
        User32.SetScrollPos(dest.Handle, Orientation.Horizontal, horizontal, true);
        User32.SetScrollPos(dest.Handle, Orientation.Vertical, vertical, true);
    }

    protected override void WndProc(ref Message m)
    {
        //process the message
        base.WndProc(ref m);

        //pass scroll messages onto any linked views
        if (m.Msg == User32.WM_VSCROLL || m.Msg == User32.WM_MOUSEWHEEL)
        {
            foreach (var linkedTreeView in linkedTreeViews)
            {
                //set the scroll positions of the linked tree view
                SetScrollPositions(this, linkedTreeView);
                //copy the windows message
                Message copy = new Message
                {
                    HWnd = linkedTreeView.Handle,
                    LParam = m.LParam,
                    Msg = m.Msg,
                    Result = m.Result,
                    WParam = m.WParam
                };
                //pass the message onto the linked tree view
                linkedTreeView.RecieveWndProc(ref copy);
            }                               
        }
    }

    /// <summary>
    /// Recieves a WndProc message without passing it onto any linked treeviews.  This is useful to avoid infinite loops.
    /// </summary>
    /// <param name="m">The windows message.</param>
    private void RecieveWndProc(ref Message m)
    {
        base.WndProc(ref m);
    }

    /// <summary>
    /// Imported functions from the User32.dll
    /// </summary>
    private class User32
    {
        public const int WM_VSCROLL = 0x115;
        public const int WM_MOUSEWHEEL = 0x020A;  

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetScrollPos(IntPtr hWnd, System.Windows.Forms.Orientation nBar);

        [DllImport("user32.dll")]
        public static extern int SetScrollPos(IntPtr hWnd, System.Windows.Forms.Orientation nBar, int nPos, bool bRedraw);
    }
}

编辑:根据 MinnesotaFat 的建议添加了 WM_MOUSEWHEEL 消息的转发。

关于c# - 如何使用 slider 在两个 TreeView 中同步滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6442911/

相关文章:

c# - 在 C# 应用程序中打开本地网络上的 .chm 文件

.net - 检查 CheckedListBox 中的项目而不选择

css - 删除使用伪类添加的 JavaFX TreeCell 格式

java - 使用存储在数据库中的信息使用 struts 2 和 ajax 生成树的节点

c# phone 8.1 更改 jpeg 质量

c# - 直接设置字典元组值

c# - WPF 创建单个 block 的虚线椭圆

c# - 如何向 C# 图表添加两个不同类型的系列?

c# - Winforms 控件结合了 SplitContainer 和 TableLayoutPanel 的优点

.net - 如何在PresentationFramework中调试NullReferenceException?