Microsoft Visual C++ 2008 で、恐らく最良解決な2つのListViewの同期スクロール

 System::Windows::Forms::ListViewには、2つのListViewの同期スクロール機能がありません。
 そこで、ListViewを継承してカスタムコントロールを作るわけですが、スクロールイベントを拾っても、どこかで動作がおかしかったり、うまく同期しなかったりと、腹を立てることになります。

 というわけで、Viewプロパティが、System::Windows::Forms::View::Details限定ならば、次のようなコードでうまく動作するという事例をご紹介(納品した製品でうまく動いているのでOKだと思います)。

#pragma once

#define WIN32_LEAN_AND_MEAN
#pragma comment(lib, "user32.lib")
#include <windows.h>
#include <CommCtrl.h>

using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Collections::Generic;
using namespace System::Windows::Forms;

namespace MyControls {

public ref class MyListView : public System::Windows::Forms::ListView
{
public:
	// コンストラクタ
	MyListView()
	{
		View = System::Windows::Forms::View::Details; // Details限定

		mVScrollSynchronizedListView = nullptr;

		mOldScrollY = 0;
		mSyncScroll = false;
	}

	// 垂直スクロールを同期させるリストビュー
	[CategoryAttribute("特殊")]
	[DescriptionAttribute("垂直スクロールを同期させるリストビューを指定します")]
	property MyListView^ VScrollSynchronizedListView
	{
		MyListView^ get() {
			return mVScrollSynchronizedListView;
		}
		void set(MyListView^ x) {
			mVScrollSynchronizedListView = x;
		}
	}

	// 垂直スクロールの旧位置
	[BrowsableAttribute(false)]
	property int OldScrollY
	{
		int get() {
			return mOldScrollY;
		}
		void set(int x) {
			mOldScrollY = x;
		}
	}

	// 連動スクロール開始
	[BrowsableAttribute(false)]
	property bool SyncScroll
	{
		bool get() {
			return mSyncScroll;
		}
		void set(bool x) {
			mSyncScroll = x;
		}
	}

protected:

	// 連動スクロール用イベント処理
	virtual void WndProc(Message %m) override
	{
		ListView::WndProc(m);

		if(mSyncScroll
		&& m.Msg==WM_PAINT) {
			SCROLLINFO si;
			ZeroMemory(&si,sizeof(SCROLLINFO));
			si.cbSize = sizeof(SCROLLINFO);
			si.fMask  = SIF_POS;

			if(Items->Count
			&& ::GetScrollInfo((HWND)Handle.ToPointer(),SB_VERT,&si)) {
				if(mOldScrollY!=si.nPos) {
					if(mVScrollSynchronizedListView) {
						int dx = 0;
						int dy = (si.nPos - mOldScrollY) * Items[0]->Bounds.Height;

						mVScrollSynchronizedListView->OldScrollY = si.nPos;
						::SendMessage((HWND)mVScrollSynchronizedListView->Handle.ToPointer(),LVM_SCROLL,(WPARAM)dx,(LPARAM)dy);
					}
				}
				mOldScrollY = si.nPos;
			}
		}
	}

private:

	MyListView^ mVScrollSynchronizedListView;
	bool        mSyncScroll;
	int         mOldScrollY;
};
}

 もう、描画イベントを全部キャプチャして無理矢理スクロールしてしまえということです。

 このコントロールをフォームに2つ貼り付けて…。

listView1->VScrollSynchronizedListView = listView2;
listView2->VScrollSynchronizedListView = listView1;

listView1->SyncScroll = true;
listView2->SyncScroll = true;

とすれば、listView1とlistView2の垂直スクロールが同期します。

 勿論、水平スクロールの同期もこのコードをちょっと改造すれば対応可能です。