マウスホイールによるスクロール

Windows フォームアプリを作成する場合,マウスホイールによる画面のスクロール機能は自力で実装する必要があるようです.実現する際には,メインフォームの MouseEnter と MouseWheel イベントにそれぞれ以下のようなイベントハンドラを指定します.

using System;
using System.Drawing;
using System.Windows.Forms;

public partial class MainForm : Form {
    public MainForm() {
        InitializeComponent();
        this.MouseEnter += new EventHandler(this.MainForm_MouseEnter);
        this.MouseWheel += new MouseEventHandler(this.MainForm_MouseWheel);
    }
    
    private void MainForm_MouseEnter(object sender, EventArgs e) {
        this.Focus();
    }
    
    private void MainForm_MouseWheel(object sender, MouseEventArgs e) {
        if (Math.Abs(e.Delta) < 120) return;
        
        ScrollableControl control = (ScrollableControl)this.XXX; // スクロールさせたい画面を指定
        var scroll = control.VerticalScroll;    
        
        var maximum = 1 + scroll.Maximum - scroll.LargeChange; // ユーザが取り得る最大値
        var delta = -(e.Delta / 120) * scroll.SmallChange;
        var offset = Math.Min(Math.Max(scroll.Value + delta, scroll.Minimum), maximum);
        
        scroll.Value = offset;
        scroll.Value = offset; // 大事なことなので2回いいました
    }
}

それで,この時に嵌ったのが最後の行.無料ブログ.tokyo - このウェブサイトは販売用です! - 無料ブログ リソースおよび情報 でもあるように,control.Value = value が何故か2回に1回反映されないと言う問題が発生しました.このせいで,1回しか記述しない状態で実際に動かしてみると妙にカクカクした動きになってしまいました.

スクロールさせる方法としては,他に control.AutoScrollPosition の値を指定する方法もあるようで,こちらを使用するのが普通の方法なのかもしれません.

private void MainForm_MouseEnter(object sender, MouseEventArgs e) {
    ...
    var offset = Math.Min(Math.Max(scroll.Value + delta, scroll.Minimum), maximum);
    control.AutoScrollPosition = new Point(0, offset);
}