プログラム

【現役SEが教える】Windows Form タッチパネル使用時のスクロール描画ズレ【DataGridView】

こんにちは!現役SEのSHOです
今回は、WindowsFormApplicationの事象解決編です。
自身が実際にハマった事象について解説させていただきます。

この記事で分かること


・なぜ描画ズレが起こるのか
・タッチパネル(タッチスクリーン)使用時のスクロール(スワイプ・フリック)描画ズレの解決策

描写ズレは不具合(バグ)?

DataGridViewを用いたWindowsFormApplicationをタッチパネル搭載のPCで使用すると、スクロールした際に描画のズレが発生します。

SHO
ゆっくりスクロールすれば、正常に動作するなあ。。

この事象についてMicrosoftのVisual Studioチームが公式に回答しています。

この現象は、DataGridView コントロールにおける不具合によって必要なメッセージが送信されないため、表示領域とコントロールの座標との整合性が取れなくなり発生します。タッチ操作に起因するので、マウスによるスクロールでは発生しません。
https://docs.microsoft.com/ja-jp/archive/blogs/jpvsblog/datagridview

要するにバグ。。。
直してほしいけど直してくれなさそう。

SHO
解決できないってこと?

タッチパネル使用時のスクロール描画ズレの解決策はあるの?

解決策はあります

アプリケーション側でウィンドウ メッセージを取得し、操作することによって回避することが可能です。
具体的には、縦スクロールした場合に発生する WM_VSCROLL メッセージを捕捉し、その通知コードが SB_THUMBPOSITION であれば、SB_THUMBTRACK の通知コードをもつ WM_VSCROLL メッセージをポストします。

https://docs.microsoft.com/ja-jp/archive/blogs/jpvsblog/datagridview

バグは直さないけど解決策は用意されているよということですね。

難しく書いていますが、
要は、スクロールしてるよってメッセージがアプリでは正常に受け取れてないってことです。

肝心の解決策なのですが、Microsoft公式では、良くも悪くも丁寧に説明されています。
分かりやすく説明させていただきます。

解決策

簡単に説明すると、「.NET Framework 標準の DataGridView 」を継承した、自作DataGridViewを使用する。という方法です。

新規クラスを作成していただき、下記のコードをソースに貼り付けます。

private const int WM_VSCROLL = 0x0115;
private const int SB_THUMBPOSITION = 0x0004;
private const int SB_THUMBTRACK = 0x0005;
[System.Runtime.InteropServices.DllImport("user32")]
private static extern int PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

public class MyDataGridView : DataGridView {
  // メッセージを処理します。
  protected override void WndProc(ref Message m){
    base.WndProc(ref m);

    if (m.Msg == WM_VSCROLL){
      if (LoWord((long)m.WParam) == LoWord((long)SB_THUMBPOSITION)){
        BeginInvoke((Action<IntPtr, IntPtr>)((WParam, LParam) => {
          // SB_THUMBPOSITION を SB_THUMBTRACK に変更します。
          IntPtr testWParam = new IntPtr(SB_THUMBTRACK);
          // WM_VSCROLL メッセージを再送します。
          PostMessage(this.Handle, WM_VSCROLL, testWParam, LParam);
        }), m.WParam, m.LParam);
      }
    }
  }
 protected short LoWord(long input){
    reeturn(short)((int)input & 0xFFFF);
  }
}

そうすると、ツールボックス内に、「MyDataGridView」というGridViewが作成されているので、
そのグリッドビューを使用することで解決します!!

ココに注意

今まで使用していた、GridViewはいらなくなりますので、削除してください。
また、グリッドビューの名前が変わったことにより参照している箇所のコントロール名変更が必要となります。

終わりに

いかがだったでしょうか。
今後も自身の体験に基づいて解説をさせていただきたいと思います。
ありがとうございました。

よろしければ、EXCEL関連の便利機能紹介も行っているのでご覧ください。




  • この記事を書いた人

SHO

どうも現役SEの『SHO』です。 高卒からフリーターを経てIT企業のSEをやっています。 29歳となります。 記事は主にプログラム・DIYと サーフィンが大好きなため、サーフィンの記事についてよく書いてく可能性があるかもしれません。

-プログラム