DataGridViewはマウスホイールの水平スクロールのメッセージ (WM_MOUSEHWHEEL) に応答しないため、それでスクロールさせるにはDataGridViewを拡張する必要があります。
protected override void WndProc(ref Message m)
{
const int WM_MOUSEHWHEEL = 0x020E;
if (m.Msg == WM_MOUSEHWHEEL)
{
int delta = ((int)m.WParam.ToInt64()) >> 16;
int offset = HorizontalScrollingOffset + delta;
if (offset < 0) offset = 0;
HorizontalScrollingOffset = offset;
m.Result = IntPtr.Zero;
}
base.WndProc(ref m);
}
この方法ではWM_MOUSEHWHEELメッセージを処理しているため、このメッセージを送信するデバイスならば、タッチパッドのスクロールのジェスチャにも対応できます。
なお既定でも、垂直スクロールによる操作時にCtrlキーが押下されていると、それで水平スクロールします。
マウスポインタの移動でスクロールするようにするには、Reader modeを用います。
[DllImport("comctl32.dll", EntryPoint = "#383")] // 383は、DoReaderMode()の序数
public static extern void DoReaderMode(ref READERMODEINFO prmi);
public delegate bool ReaderScroll(ref READERMODEINFO prmi, int dx, int dy);
public delegate bool TranslateDispatch(ref MSG lpmsg);
[StructLayout(LayoutKind.Sequential)]
public struct READERMODEINFO
{
public uint cbSize;
public IntPtr hwnd;
public UInt32 fFlags;
public IntPtr prc;
public ReaderScroll pfnScroll;
public TranslateDispatch pfnTranslate;
public IntPtr lParam;
}
[StructLayout(LayoutKind.Sequential)]
public struct MSG
{
public IntPtr hwnd;
public uint message;
public IntPtr wParam;
public IntPtr lParam;
public UInt32 time;
public POINT pt;
public UInt32 lPrivate;
}
[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
public Int32 x;
public Int32 y;
}
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public Int32 left;
public Int32 top;
public Int32 right;
public Int32 bottom;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Middle)
{
// マウスの中ボタンの押下で、Reader modeに入る
EnterReaderMode(e.Location);
}
}
private void EnterReaderMode(Point point)
{
// カーソルのサイズを基準に、スクロール領域を算出
Size size = Cursor.Current.Size;
int width = size.Width / 2;
int height = size.Height / 2;
RECT scrollingArea = new RECT
{
left = point.X - width,
right = point.X + width,
top = point.Y - height,
bottom = point.Y + height,
};
IntPtr pScrollingArea = Marshal.AllocHGlobal(Marshal.SizeOf<RECT>());
Marshal.StructureToPtr(scrollingArea, pScrollingArea, false);
const uint RMF_ZEROCURSOR = 0x01;
READERMODEINFO readerInfo = new READERMODEINFO
{
cbSize = (uint)Marshal.SizeOf<READERMODEINFO>(),
hwnd = Handle,
fFlags = RMF_ZEROCURSOR,
prc = pScrollingArea,
pfnScroll = new ReaderScroll(ReaderScrollCallback),
pfnTranslate = new TranslateDispatch(TranslateDispatchCallback),
lParam = IntPtr.Zero,
};
DoReaderMode(ref readerInfo);
Marshal.FreeHGlobal(pScrollingArea);
}
private bool ReaderScrollCallback(ref READERMODEINFO prmi, int dx, int dy)
{
// コントロールをスクロールする
HorizontalScrollingOffset += dy;
FirstDisplayedScrollingRowIndex += dy;
return true;
}
private bool TranslateDispatchCallback(ref MSG lpmsg)
{
return false;
}