トップ回答者
【タブレット】WebBrowerに一つの指で上へ・下へスクロールすると、WebBrowerに表示されたコンテンツをスクロールするのではなく、ウィンドウをスクロールすることになってしまった。

質問
-
みなさん、こんにちは、Icyfireです。
現在、タブレットで下記の現象が起こってしまいました。
現象:
WPF画面にWebBrowerが存在しますと、
WebBrowerに表示されたJsp WebPageに一つの指で上へ/下へスクロールしますと、
表示されたWebPageの内容をスクロールしているのではなく、WPF画面全体が少し上へ・下へずれていて、
後ろのTaskbarが見えてしまいました。
指を離すと、WPF画面が元の位置に戻っています。もちろんTaskbarも見えなくなります。
この現象をどうすれば解消できるか、
どなた様が教えていただけないでしょうか。
その原因も一緒に教えていただけるとありがたいです。
以上、よろしくお願い致します。
回答
-
境界域フィードバック(Boundary Feedback)というやつです。
タッチによるスクロールをした時に端までスクロールしたことを視覚的にわかりやすくするため、動かした方向にWindow全体がピョコっと動きます。
タッチ対応しているアプリケーションの標準の動作です。WPFだとManipulationBoundaryFeedbackイベントでe.Handles=trueにすると無効にできるはずなんですが、WebBrowserは特殊なのでその方法では対応できません。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Documents; using System.Runtime.InteropServices; namespace WpfApplication1 { public partial class MainWindow : Window { private System.Windows.Controls.WebBrowser _webbrowserObj; public MainWindow() { InitializeComponent(); _webbrowserObj = new System.Windows.Controls.WebBrowser(); _webbrowserObj.LoadCompleted += _webbrowserObj_LoadCompleted; _webbrowserObj.Navigate(@"https://social.msdn.microsoft.com/Forums/ja-JP/home"); this.Content = _webbrowserObj; } BrowserNativeWindow hookwindow; void _webbrowserObj_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) { if (hookwindow == null) { hookwindow = BrowserNativeWindow.Hook(this._webbrowserObj); if (hookwindow != null) { _webbrowserObj.LoadCompleted -= _webbrowserObj_LoadCompleted; } } } } class BrowserNativeWindow : System.Windows.Forms.NativeWindow { private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); public static List<IntPtr> GetChildWindows(IntPtr hwndParent) { List<IntPtr> list = new List<IntPtr>(); EnumChildWindows(hwndParent, (h, p) => { list.Add(h); return true; }, IntPtr.Zero); return list; } [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo); [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseGestureInfoHandle(IntPtr hGestureInfo); [StructLayout(LayoutKind.Sequential)] private struct POINTS { public short x; public short y; } [StructLayout(LayoutKind.Sequential)] private struct GESTUREINFO { public int cbSize; public int dwFlags; public int dwID; public IntPtr hwndTarget; [MarshalAs(UnmanagedType.Struct)] public POINTS ptsLocation; public int dwInstanceID; public int dwSequenceID; public UInt64 ullArguments; public uint cbExtraArgs; } private enum GID : int { BEGIN = 1, END = 2, ZOOM = 3, PAN = 4 } private const int WM_GESTURE = 0x0119; public static BrowserNativeWindow Hook(System.Windows.Controls.WebBrowser browser) { var host = browser as System.Windows.Interop.HwndHost; IntPtr hwnd = host.Handle; var children = BrowserNativeWindow.GetChildWindows(hwnd); foreach (IntPtr child in BrowserNativeWindow.GetChildWindows(hwnd)) { var target = GetChildWindows(child).FirstOrDefault(); if (target != IntPtr.Zero) { var nw = new BrowserNativeWindow(); nw.AssignHandle(target); nw.browser = browser; return nw; } } return null; } private System.Windows.Controls.WebBrowser browser; private POINTS startLocatoion;//開始したときの指の位置 private Point startScroll;//開始したときのスクロールバーを覚えておく protected override void WndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_GESTURE) { GESTUREINFO ginfo = new GESTUREINFO(); ginfo.cbSize = Marshal.SizeOf(typeof(GESTUREINFO)); if (GetGestureInfo(m.LParam, ref ginfo)) { CloseGestureInfoHandle(m.LParam); } var doc = browser.Document as mshtml.HTMLDocument; mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.documentElement; switch ((GID)m.WParam.ToInt32()) { case GID.BEGIN: //スクロール開始位置記憶 startLocatoion = ginfo.ptsLocation; startScroll = new Point(elem.scrollLeft, elem.scrollTop); break; case GID.END: break; case GID.ZOOM: return;//ズーム禁止 case GID.PAN: //スクロールを処理する elem.scrollLeft =(int) Math.Min(Math.Max(0, startScroll.X - ginfo.ptsLocation.x + startLocatoion.x), elem.scrollWidth - elem.clientWidth); elem.scrollTop = (int)Math.Min(Math.Max(0, startScroll.Y - ginfo.ptsLocation.y + startLocatoion.y), elem.scrollHeight - elem.clientHeight); return; } } base.WndProc(ref m); } } }
そのため小細工してやらないと無効にできないです。#ブラウザ内のフレームやリストにスクロールバーがあるうまくいかないかも
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2016年11月26日 15:03 貼り付けミス訂正
- 回答の候補に設定 栗下 望Microsoft employee, Moderator 2016年11月28日 0:22
- 回答としてマーク icyfire028 2016年11月28日 12:36
すべての返信
-
境界域フィードバック(Boundary Feedback)というやつです。
タッチによるスクロールをした時に端までスクロールしたことを視覚的にわかりやすくするため、動かした方向にWindow全体がピョコっと動きます。
タッチ対応しているアプリケーションの標準の動作です。WPFだとManipulationBoundaryFeedbackイベントでe.Handles=trueにすると無効にできるはずなんですが、WebBrowserは特殊なのでその方法では対応できません。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Documents; using System.Runtime.InteropServices; namespace WpfApplication1 { public partial class MainWindow : Window { private System.Windows.Controls.WebBrowser _webbrowserObj; public MainWindow() { InitializeComponent(); _webbrowserObj = new System.Windows.Controls.WebBrowser(); _webbrowserObj.LoadCompleted += _webbrowserObj_LoadCompleted; _webbrowserObj.Navigate(@"https://social.msdn.microsoft.com/Forums/ja-JP/home"); this.Content = _webbrowserObj; } BrowserNativeWindow hookwindow; void _webbrowserObj_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) { if (hookwindow == null) { hookwindow = BrowserNativeWindow.Hook(this._webbrowserObj); if (hookwindow != null) { _webbrowserObj.LoadCompleted -= _webbrowserObj_LoadCompleted; } } } } class BrowserNativeWindow : System.Windows.Forms.NativeWindow { private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); public static List<IntPtr> GetChildWindows(IntPtr hwndParent) { List<IntPtr> list = new List<IntPtr>(); EnumChildWindows(hwndParent, (h, p) => { list.Add(h); return true; }, IntPtr.Zero); return list; } [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo); [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseGestureInfoHandle(IntPtr hGestureInfo); [StructLayout(LayoutKind.Sequential)] private struct POINTS { public short x; public short y; } [StructLayout(LayoutKind.Sequential)] private struct GESTUREINFO { public int cbSize; public int dwFlags; public int dwID; public IntPtr hwndTarget; [MarshalAs(UnmanagedType.Struct)] public POINTS ptsLocation; public int dwInstanceID; public int dwSequenceID; public UInt64 ullArguments; public uint cbExtraArgs; } private enum GID : int { BEGIN = 1, END = 2, ZOOM = 3, PAN = 4 } private const int WM_GESTURE = 0x0119; public static BrowserNativeWindow Hook(System.Windows.Controls.WebBrowser browser) { var host = browser as System.Windows.Interop.HwndHost; IntPtr hwnd = host.Handle; var children = BrowserNativeWindow.GetChildWindows(hwnd); foreach (IntPtr child in BrowserNativeWindow.GetChildWindows(hwnd)) { var target = GetChildWindows(child).FirstOrDefault(); if (target != IntPtr.Zero) { var nw = new BrowserNativeWindow(); nw.AssignHandle(target); nw.browser = browser; return nw; } } return null; } private System.Windows.Controls.WebBrowser browser; private POINTS startLocatoion;//開始したときの指の位置 private Point startScroll;//開始したときのスクロールバーを覚えておく protected override void WndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_GESTURE) { GESTUREINFO ginfo = new GESTUREINFO(); ginfo.cbSize = Marshal.SizeOf(typeof(GESTUREINFO)); if (GetGestureInfo(m.LParam, ref ginfo)) { CloseGestureInfoHandle(m.LParam); } var doc = browser.Document as mshtml.HTMLDocument; mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.documentElement; switch ((GID)m.WParam.ToInt32()) { case GID.BEGIN: //スクロール開始位置記憶 startLocatoion = ginfo.ptsLocation; startScroll = new Point(elem.scrollLeft, elem.scrollTop); break; case GID.END: break; case GID.ZOOM: return;//ズーム禁止 case GID.PAN: //スクロールを処理する elem.scrollLeft =(int) Math.Min(Math.Max(0, startScroll.X - ginfo.ptsLocation.x + startLocatoion.x), elem.scrollWidth - elem.clientWidth); elem.scrollTop = (int)Math.Min(Math.Max(0, startScroll.Y - ginfo.ptsLocation.y + startLocatoion.y), elem.scrollHeight - elem.clientHeight); return; } } base.WndProc(ref m); } } }
そのため小細工してやらないと無効にできないです。#ブラウザ内のフレームやリストにスクロールバーがあるうまくいかないかも
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 編集済み gekkaMVP 2016年11月26日 15:03 貼り付けミス訂正
- 回答の候補に設定 栗下 望Microsoft employee, Moderator 2016年11月28日 0:22
- 回答としてマーク icyfire028 2016年11月28日 12:36
-
境界域フィードバック(Boundary Feedback)というやつです。
タッチによるスクロールをした時に端までスクロールしたことを視覚的にわかりやすくするため、動かした方向にWindow全体がピョコっと動きます。
タッチ対応しているアプリケーションの標準の動作です。WPFだとManipulationBoundaryFeedbackイベントでe.Handles=trueにすると無効にできるはずなんですが、WebBrowserは特殊なのでその方法では対応できません。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Documents; using System.Runtime.InteropServices; namespace WpfApplication1 { public partial class MainWindow : Window { private System.Windows.Controls.WebBrowser _webbrowserObj; public MainWindow() { InitializeComponent(); _webbrowserObj = new System.Windows.Controls.WebBrowser(); _webbrowserObj.LoadCompleted += _webbrowserObj_LoadCompleted; _webbrowserObj.Navigate(@"https://social.msdn.microsoft.com/Forums/ja-JP/home"); this.Content = _webbrowserObj; } BrowserNativeWindow hookwindow; void _webbrowserObj_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) { if (hookwindow == null) { hookwindow = BrowserNativeWindow.Hook(this._webbrowserObj); if (hookwindow != null) { _webbrowserObj.LoadCompleted -= _webbrowserObj_LoadCompleted; } } } } class BrowserNativeWindow : System.Windows.Forms.NativeWindow { private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); public static List<IntPtr> GetChildWindows(IntPtr hwndParent) { List<IntPtr> list = new List<IntPtr>(); EnumChildWindows(hwndParent, (h, p) => { list.Add(h); return true; }, IntPtr.Zero); return list; } [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo); [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseGestureInfoHandle(IntPtr hGestureInfo); [StructLayout(LayoutKind.Sequential)] private struct POINTS { public short x; public short y; } [StructLayout(LayoutKind.Sequential)] private struct GESTUREINFO { public int cbSize; public int dwFlags; public int dwID; public IntPtr hwndTarget; [MarshalAs(UnmanagedType.Struct)] public POINTS ptsLocation; public int dwInstanceID; public int dwSequenceID; public UInt64 ullArguments; public uint cbExtraArgs; } private enum GID : int { BEGIN = 1, END = 2, ZOOM = 3, PAN = 4 } private const int WM_GESTURE = 0x0119; public static BrowserNativeWindow Hook(System.Windows.Controls.WebBrowser browser) { var host = browser as System.Windows.Interop.HwndHost; IntPtr hwnd = host.Handle; var children = BrowserNativeWindow.GetChildWindows(hwnd); foreach (IntPtr child in BrowserNativeWindow.GetChildWindows(hwnd)) { var target = GetChildWindows(child).FirstOrDefault(); if (target != IntPtr.Zero) { var nw = new BrowserNativeWindow(); nw.AssignHandle(target); nw.browser = browser; return nw; } } return null; } private System.Windows.Controls.WebBrowser browser; private POINTS startLocatoion;//開始したときの指の位置 private Point startScroll;//開始したときのスクロールバーを覚えておく protected override void WndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_GESTURE) { GESTUREINFO ginfo = new GESTUREINFO(); ginfo.cbSize = Marshal.SizeOf(typeof(GESTUREINFO)); if (GetGestureInfo(m.LParam, ref ginfo)) { CloseGestureInfoHandle(m.LParam); } var doc = browser.Document as mshtml.HTMLDocument; mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.documentElement; switch ((GID)m.WParam.ToInt32()) { case GID.BEGIN: //スクロール開始位置記憶 startLocatoion = ginfo.ptsLocation; startScroll = new Point(elem.scrollLeft, elem.scrollTop); break; case GID.END: break; case GID.ZOOM: return;//ズーム禁止 case GID.PAN: //スクロールを処理する elem.scrollLeft =(int) Math.Min(Math.Max(0, startScroll.X - ginfo.ptsLocation.x + startLocatoion.x), elem.scrollWidth - elem.clientWidth); elem.scrollTop = (int)Math.Min(Math.Max(0, startScroll.Y - ginfo.ptsLocation.y + startLocatoion.y), elem.scrollHeight - elem.clientHeight); return; } } base.WndProc(ref m); } } }
そのため小細工してやらないと無効にできないです。#ブラウザ内のフレームやリストにスクロールバーがあるうまくいかないかも
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
ご返信有難うございました。
頂いたソースで確認したところ、
画面ずれるの件は解決できましたが、
Broswerに表示された内容もスクロールできなくなりました。
☆直接スクロールバーをクリックするなら、問題ありません。
-
境界域フィードバック(Boundary Feedback)というやつです。
タッチによるスクロールをした時に端までスクロールしたことを視覚的にわかりやすくするため、動かした方向にWindow全体がピョコっと動きます。
タッチ対応しているアプリケーションの標準の動作です。WPFだとManipulationBoundaryFeedbackイベントでe.Handles=trueにすると無効にできるはずなんですが、WebBrowserは特殊なのでその方法では対応できません。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Documents; using System.Runtime.InteropServices; namespace WpfApplication1 { public partial class MainWindow : Window { private System.Windows.Controls.WebBrowser _webbrowserObj; public MainWindow() { InitializeComponent(); _webbrowserObj = new System.Windows.Controls.WebBrowser(); _webbrowserObj.LoadCompleted += _webbrowserObj_LoadCompleted; _webbrowserObj.Navigate(@"https://social.msdn.microsoft.com/Forums/ja-JP/home"); this.Content = _webbrowserObj; } BrowserNativeWindow hookwindow; void _webbrowserObj_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e) { if (hookwindow == null) { hookwindow = BrowserNativeWindow.Hook(this._webbrowserObj); if (hookwindow != null) { _webbrowserObj.LoadCompleted -= _webbrowserObj_LoadCompleted; } } } } class BrowserNativeWindow : System.Windows.Forms.NativeWindow { private delegate bool EnumWindowsProc(IntPtr hwnd, IntPtr lParam); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam); public static List<IntPtr> GetChildWindows(IntPtr hwndParent) { List<IntPtr> list = new List<IntPtr>(); EnumChildWindows(hwndParent, (h, p) => { list.Add(h); return true; }, IntPtr.Zero); return list; } [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetGestureInfo(IntPtr hGestureInfo, ref GESTUREINFO pGestureInfo); [DllImport("user32")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CloseGestureInfoHandle(IntPtr hGestureInfo); [StructLayout(LayoutKind.Sequential)] private struct POINTS { public short x; public short y; } [StructLayout(LayoutKind.Sequential)] private struct GESTUREINFO { public int cbSize; public int dwFlags; public int dwID; public IntPtr hwndTarget; [MarshalAs(UnmanagedType.Struct)] public POINTS ptsLocation; public int dwInstanceID; public int dwSequenceID; public UInt64 ullArguments; public uint cbExtraArgs; } private enum GID : int { BEGIN = 1, END = 2, ZOOM = 3, PAN = 4 } private const int WM_GESTURE = 0x0119; public static BrowserNativeWindow Hook(System.Windows.Controls.WebBrowser browser) { var host = browser as System.Windows.Interop.HwndHost; IntPtr hwnd = host.Handle; var children = BrowserNativeWindow.GetChildWindows(hwnd); foreach (IntPtr child in BrowserNativeWindow.GetChildWindows(hwnd)) { var target = GetChildWindows(child).FirstOrDefault(); if (target != IntPtr.Zero) { var nw = new BrowserNativeWindow(); nw.AssignHandle(target); nw.browser = browser; return nw; } } return null; } private System.Windows.Controls.WebBrowser browser; private POINTS startLocatoion;//開始したときの指の位置 private Point startScroll;//開始したときのスクロールバーを覚えておく protected override void WndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_GESTURE) { GESTUREINFO ginfo = new GESTUREINFO(); ginfo.cbSize = Marshal.SizeOf(typeof(GESTUREINFO)); if (GetGestureInfo(m.LParam, ref ginfo)) { CloseGestureInfoHandle(m.LParam); } var doc = browser.Document as mshtml.HTMLDocument; mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.documentElement; switch ((GID)m.WParam.ToInt32()) { case GID.BEGIN: //スクロール開始位置記憶 startLocatoion = ginfo.ptsLocation; startScroll = new Point(elem.scrollLeft, elem.scrollTop); break; case GID.END: break; case GID.ZOOM: return;//ズーム禁止 case GID.PAN: //スクロールを処理する elem.scrollLeft =(int) Math.Min(Math.Max(0, startScroll.X - ginfo.ptsLocation.x + startLocatoion.x), elem.scrollWidth - elem.clientWidth); elem.scrollTop = (int)Math.Min(Math.Max(0, startScroll.Y - ginfo.ptsLocation.y + startLocatoion.y), elem.scrollHeight - elem.clientHeight); return; } } base.WndProc(ref m); } } }
そのため小細工してやらないと無効にできないです。#ブラウザ内のフレームやリストにスクロールバーがあるうまくいかないかも
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
ご返信有難うございました。
頂いたソースで確認したところ、
画面ずれるの件は解決できましたが、
Broswerに表示された内容もスクロールできなくなりました。
☆直接スクロールバーをクリックするなら、問題ありません。
申し訳ございません。
問題が解決できました。
WebBrowerに表示されたスクロールバーはWebBrowerのスクロールバーではなく、表示されたJSPファイルの中にあるDIVのスクロールバーです。
下記のコードのみを変更することで、解決できました。
mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.documentElement;
↓
mshtml.IHTMLElement2 elem = (mshtml.IHTMLElement2)doc.getElementById("schedule-list");
☆schedule-list は DivのIDです。
以上、よろしくお願い致します。