问题描述
我正在使用 Visual Studio 2010 (C#) 和 Windows 窗体应用程序.
I am using Visual Studio 2010 (C#) and a Windows Forms application.
我有两个并排的树视图,我想出了如何使用滚动条上的向上/向下按钮同步滚动,但是当我使用滑块时,它不会移动另一个树视图.我采用了一个有效的列表视图示例,但相同的代码不适用于树视图.
I have two treeviews side by side, and I have figured out how to synchronise the scrolling using the up/down buttons on the scrollbar, but when I use the slider it does not move the other treeview. I have taken a listview example that works, but the same code does not work for treeviews.
到目前为止,我有,主要形式:
So far I have, in the main form:
[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);
}
}
我在表单中添加了两个.
which I add two of to the form.
我可以使用相同的代码让 listivew 控制树视图,如果您拖动滑块,这将起作用,但反过来,它仅适用于向上向下按钮.
I can use the same code to have a listivew control the treeview and that will work if you drag the slider, but in reverse it only works with the up down buttons.
推荐答案
您可以使用 GetScrollPos
和 SetScrollPos
函数,而不是使用 SendMessage 并将您的 DLL 标记为不安全user32.dll.
Rather than use SendMessage and mark your DLL as unsafe you can use the GetScrollPos
and SetScrollPos
functions from user32.dll.
我已将代码封装到您的 MyTreeView 类中,以便对其进行很好的封装.
I've wrapped the code up into your MyTreeView class so it's nicely encapsulated.
您只需要像这样调用 AddLinkedTreeView
方法:
You just need to call the AddLinkedTreeView
method like so:
treeView1.AddLinkedTreeView(treeView2);
这是 MyTreeView 类的源代码.
Here's the source for the MyTreeView class.
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 消息的转发.
Edit: Added forwarding of the WM_MOUSEWHEEL message as per MinnesotaFat's suggestion.
这篇关于如何使用滑块在两个树视图中同步滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!