2011-06-22 15 views
2

Visual  スタジオ  2010(C#)とWindowsフォームアプリケーションを使用しています。スライダーを使用して2つのツリービューでスクロールを同期させる方法

2つのツリービューが並べてあり、スクロールバーの上下ボタンを使用してスクロールを同期する方法を考えましたが、スライダを使用すると他のツリービューは移動しません。私は動作するlistviewの例を取っ​​たが、同じコードはtreeviewsのために働かない。

これまでのところ私は、メインフォームでいる:

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

} 

私は、フォームへの2を追加しました。

同じコードを使用してlistivewでツリービューを制御することができます。スライダをドラッグすると機能しますが、逆に上のボタンでのみ機能します。

+0

誰もが。ネットはhttp://www.pinvoke.net/を非常に便利に見いだします。それは素晴らしいリソースであり、私はそれが非常に貴重であることを発見しました。 –

答えて

7

むしろ以下のようにしてください。 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メッセージを追加しましたフォワーディング。

+0

いつ呼び出すのですか 'treeView1.AddLinkedTreeView(treeView2);'正確に?私は.net 2.0を持っており、ツリービューのスクロールイベントはありません... – asdasdad

2

私は前TextBoxesでこれを行っているが、私は解決策が同様にあなたのために働くべきだと思う:

// Get/Set Scroll positions of a control handle 
private unsafe Win32.POINT GetScrollPos(System.IntPtr myHandle) 
{ 
    Win32.POINT res = new Win32.POINT(); 
    IntPtr ptr = new IntPtr(&res); 
    Win32.SendMessage(myHandle, Win32.EM_GETSCROLLPOS, 0, ptr); 
    return res; 
} 

private unsafe void SetScrollPos(Win32.POINT point, System.IntPtr myHandle) 
{ 
    IntPtr ptr = new IntPtr(&point); 
    Win32.SendMessage(myHandle, Win32.EM_SETSCROLLPOS, 0, ptr); 
} 

Win32のは、それからちょうどListViewスクロールイベントの両方に接続

public const int WM_USER = 0x400; 
public const int EM_GETSCROLLPOS = (WM_USER + 221); 
public const int EM_SETSCROLLPOS = (WM_USER + 222); 

[StructLayout(LayoutKind.Sequential)] 
public struct POINT 
{ 
    public int x; 
    public int y; 
} 

[DllImport("user32")] public static extern int SendMessage(
    HWND hwnd, int wMsg, int wParam, IntPtr lParam); 

の詳細を

private void ListView1Scrolled(object sender, System.EventArgs e) 
{ 
    SetScrollPos(GetScrollPos(ListView1.Handle), ListView2.Handle); 
} 

private void ListView2Scrolled(object sender, System.EventArgs e) 
{ 
    SetScrollPos(GetScrollPos(ListView2.Handle), ListView1.Handle); 
} 
1

DoctaJonez '答えは素晴らしいです。完全性のためにあなたがWndProc方法でifステートメントに別の条件を追加した場合、あなたにも、マウスホイールのスクロールイベントを処理することができます

if (m.Msg == WM_VSCROLL || m.Msg == WM_MOUSEWHEEL) 

そしてWM_MOUSEWHEEL宣言:からのWin32を使用して

private cont int WM_MOUSEWHEEL = 0x020A; 
関連する問題