2011-01-27 44 views
9

WinFormsでは、項目のドラッグを開始するためにDoDragDropを呼び出した後、マウスホイールでスクロールしなくなり、コントロールのMouseWheelイベントが呼び出されなくなります。ドラッグ&ドロップ中にマウスホイールを使用できますか?

ドラッグ中にマウスホイールを操作する方法はありますか?

+0

私はちょうどそれについて今日見つけたように私はこれについて肯定的ではありません。しかし、あなたはRxで何を求めているのですか? –

+0

'MouseWheel'イベントがマウスの上にあるコントロールの代わりにドラッグソース*に渡されているかどうかを確認して見ることができますか? –

+0

したがって、オブジェクトをスクロールしたフォームにドロップするか、フォームに収まらない大きなオブジェクトをドロップします。私は正しいですか? –

答えて

6

あなたが得ることができるグローバルMouseWheelそれがより明確にするために頑張ります。

using System; 
using System.ComponentModel; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 
using Microsoft.Win32.SafeHandles; 

using BOOL = System.Boolean; 
using DWORD = System.UInt32; 
using HHOOK = SafeHookHandle; 
using HINSTANCE = System.IntPtr; 
using HOOKPROC = HookProc; 
using LPARAM = System.IntPtr; 
using LRESULT = System.IntPtr; 
using POINT = System.Drawing.Point; 
using ULONG_PTR = System.IntPtr; 
using WPARAM = System.IntPtr; 

public delegate LRESULT HookProc(int nCode, WPARAM wParam, LPARAM lParam); 

internal static class NativeMethods 
{ 
    [DllImport("User32.dll", SetLastError = true)] 
    internal static extern HHOOK SetWindowsHookEx(
     HookType idHook, 
     HOOKPROC lpfn, 
     HINSTANCE hMod, 
     DWORD dwThreadId); 

    [DllImport("User32.dll")] 
    internal static extern LRESULT CallNextHookEx(
     HHOOK hhk, 
     int nCode, 
     WPARAM wParam, 
     LPARAM lParam); 

    [DllImport("User32.dll", SetLastError = true)] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    internal static extern BOOL UnhookWindowsHookEx(
     IntPtr hhk); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    public static extern IntPtr GetModuleHandle(string lpModuleName); 
} 

internal static class NativeTypes 
{ 
    internal enum MSLLHOOKSTRUCTFlags : uint 
    { 
     LLMHF_INJECTED = 0x00000001U, 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    internal struct MSLLHOOKSTRUCT 
    { 
     internal POINT pt; 
     internal DWORD mouseData; 
     internal MSLLHOOKSTRUCTFlags flags; 
     internal DWORD time; 
     internal ULONG_PTR dwExtraInfo; 
    } 
} 

internal static class NativeConstants 
{ 
    internal const int WH_MOUSE_LL = 14; 

    internal const int HC_ACTION = 0; 

    internal const int WM_MOUSEWHEEL = 0x020A; 
    internal const int WM_MOUSEHWHEEL = 0x020E; 

    internal const int WHEEL_DELTA = 120; 
} 

public enum HookType 
{ 
    LowLevelMouseHook = NativeConstants.WH_MOUSE_LL 
} 

public enum HookScope 
{ 
    LowLevelGlobal, 
} 

public class SafeHookHandle : SafeHandleZeroOrMinusOneIsInvalid 
{ 
    private SafeHookHandle() : base(true) { } 

    public static SafeHookHandle SetWindowsHook(HookType idHook, HookProc lpfn, IntPtr hMod, uint dwThreadId) 
    { 
     var hhk = NativeMethods.SetWindowsHookEx(idHook, lpfn, hMod, dwThreadId); 

     if(hhk.IsInvalid) 
     { 
      throw new Win32Exception(); 
     } 
     else 
     { 
      return hhk; 
     } 
    } 

    public IntPtr CallNextHook(int nCode, IntPtr wParam, IntPtr lParam) 
    { 
     return NativeMethods.CallNextHookEx(this, nCode, wParam, lParam); 
    } 

    protected override bool ReleaseHandle() 
    { 
     return NativeMethods.UnhookWindowsHookEx(this.handle); 
    } 
} 

public abstract class WindowsHook : IDisposable 
{ 
    private SafeHookHandle hhk; 
    private HookProc lpfn; 

    protected WindowsHook(HookType idHook, HookScope scope) 
    { 
     this.lpfn = this.OnWindowsHook; 

     switch(scope) 
     { 
      case HookScope.LowLevelGlobal: 
       IntPtr moduleHandle = NativeMethods.GetModuleHandle(null); 
       this.hhk = SafeHookHandle.SetWindowsHook(idHook, this.lpfn, moduleHandle, 0U); 
       return; 
      default: 
       throw new InvalidEnumArgumentException("scope", (int)scope, typeof(HookScope)); 
     } 
    } 

    protected virtual IntPtr OnWindowsHook(int nCode, IntPtr wParam, IntPtr lParam) 
    { 
     return this.hhk.CallNextHook(nCode, wParam, lParam); 
    } 

    public void Dispose() 
    { 
     this.Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if(disposing) 
     { 
      if(this.hhk != null) { this.hhk.Dispose(); } 
     } 
    } 
} 

public class LowLevelMouseHook : WindowsHook 
{ 
    public event MouseEventHandler MouseWheel; 

    public LowLevelMouseHook() : base(HookType.LowLevelMouseHook, HookScope.LowLevelGlobal) { } 

    protected sealed override IntPtr OnWindowsHook(int nCode, IntPtr wParam, IntPtr lParam) 
    { 
     if(nCode == NativeConstants.HC_ACTION) 
     { 
      var msLLHookStruct = (NativeTypes.MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(NativeTypes.MSLLHOOKSTRUCT)); 

      switch(wParam.ToInt32()) 
      { 
       case NativeConstants.WM_MOUSEWHEEL: 
       case NativeConstants.WM_MOUSEHWHEEL: 
        this.OnMouseWheel(new MouseEventArgs(Control.MouseButtons, 0, msLLHookStruct.pt.X, msLLHookStruct.pt.Y, (int)msLLHookStruct.mouseData >> 16)); 
        break; 
      } 
     } 

     return base.OnWindowsHook(nCode, wParam, lParam); 
    } 

    protected virtual void OnMouseWheel(MouseEventArgs e) 
    { 
     if(this.MouseWheel != null) 
     { 
      this.MouseWheel(this, e); 
     } 
    } 
} 

使用例:

using (LowLevelMouseHook hook = new LowLevelMouseHook()) 
{ 
    hook.MouseWheel += (sender, e) => 
    { 
     Console.WriteLine(e.Delta); 
    }; 
    Application.Run(); 
} 

コードは、組み込みウィンドウからのイベントは、コントロールクラスを形成するように振る舞うイベントMouseWheelLowLevelMouseHookでクラスを提供します。

は(また、コードは他のフックで使用するための抽象クラスWindowsHooksに分割され、ハンドルを確実にするためにSafeHookHandleクラスが解放され、ネイティブメソッドのためのヘルパークラス)

あなたがSetWindowsHookExを見て必要がありますCALLBACK LowLevelMouseProcこれの背後にある技術を理解する。


このイベント

は、あなたのアプリケーションに限定されるものではなく、フォームの外にマウスをキャプチャしますので、それはまた、あなたが地元のイベントを使用することはできませんあなたの操作のために働く必要があります。

+0

うーん..残念なことに、これはうまくいかないようです - プログラムを起動しようとすると、* "モジュールハンドルなしで非ローカルフックを設定できません" *。 'SafeHookHandle.SetWindowsHook.hMod'は' IntPtr.Zero'にはなりません... –

+0

'IntPtr.Zero'ではなく' GetModuleHandle(null) 'の結果を使っているようです - これを編集します。正確に私が探していたもの..ありがとう! –

+0

ようこそ。帽子のIntPtr.Zeroに問題がありましたが、突然(Win7 x64)消えてしまいました。 – riel

4

いいえ、D + Dの間に識別可能なフォーカスはなく、D + Dイベントはマウスホイールの動きを戻して報告しません。典型的なやり方は、DragOverを使用して、ドラッグするカーソルがスクロール可能領域の両端に近いかどうかをチェックすることです。タイマーでスクロールしてください。例is here

+0

ええ、私はそれをやっているが、私もマウスホイールが動作したい。ちょっと、私は簡単な解決策を望んでいた。グローバルマウスイベント(P/Invoke経由)でこれを行う方法を知っているとは思いませんか? –

+0

IMessageFilterはそれを実行できます。それは簡単な解決策ではありません。 –

+0

いいえ、取り消してください、フォーカスが暗いです。非常に多分。 –

2

組み込みのD + D機能を使用してPInvokeやその他のイベントでその動作を上書きしようとする代わりに、マウスの上下のイベントに基づいて独自のドラッグ&ドロップシステムを作成して、フォームのマウスホイールスクロール機能

模擬ドラッグソース(マウスを下にドラッグするとアクティブにする)であるラベルとマウスホイールのスクロール可能な任意のアイテムで構成されるリストボックスを含むテストフォームの非常に単純な例ですドロップ先。このようなサンプルを実行すると、ラベルのマウスダウンイベントでカーソルを変更し、リストボックスの上にドラッグしてマウスホイールでスクロールすると、期待どおりに動作することがわかります。リストボックスがスクロールします。あなたは(たとえば、ドロップ・プロセスを定義するためのハンドラアップマウスなど)の項目を削除するための独自のロジックを配線する必要があり、あなたはおそらくSizeAllカーソルが、より多くの何かを使用したくないもちろん

using System; 
using System.Windows.Forms; 

public partial class Form1 : Form { 
    public Form1() { 
     InitializeComponent(); 
    } 

    private void Form1_Load(object sender, EventArgs e) { 
     for (int i=0; i<250; i++) listBox1.Items.Add("item " + i); 
    } 

    private void Label1MouseDown(object sender, MouseEventArgs e) { 
     Cursor.Current = Cursors.SizeAll; 
    } 
} 

ドラッグアンドドロップを示す。このサンプルは、独自のD + Dの管理がAPIブラックボックスを上書きしようとするより簡単かもしれないことを示しています。マウスポインタが終わりまたは初めに到達した客観的データグリッド(あなたがドロップすると仮定1)、で、あなたはスクロールダウンまたはアップ(もちろん、それは制御されます開始

:これはどのように

+0

この作業を行うには、マウスをキャプチャしないことが重要です。 –

+0

@Ben:私の提案は実際にマウスを捕捉するのではなく、マウスダウンイベントでカーソルを変更するだけです。あなたが見るスニペットは、文字通り、これをテストするために必要なすべてのものです。もちろん、自動生成されたデザイナーファイルとは異なります。すべてのOPがこれを完了するために必要なのは、フラグ、マウスアップハンドラを適切なコントロールに追加すること、そしてドロップがするはずのロジックを追加することです。 –

+0

正確です。あなたのコードとフレームワークコードの違いは、フレームワークがマウスをキャプチャしないことです。 –

1

mousein/mouseoutイベント)。

エクセルのオブジェクトをドラッグして試してみてください。最後に到達すると、下から上にスクロールし始めます。私は自分自身を説明する場合、私は知らない

は、私が知っていると私は、キーボードフック付き

+0

はい、私は[既にそれをしています](http://stackoverflow.com/questions/2567809/how-to-autoscroll-a-datagridview-during-drag- and-drop/2568199#2568199) - これはこの制限のための回避策であり修正ではありません。 –

関連する問題