子のコントロールの下にムセモブイベントをキャプチャする方法
質問
マウスカーソルが一連の座標の間に落ちた場合に発射する特定のフォームでMouseClickイベントを処理しようとしています - 正方形にしてください。
空のフォームがあれば、単にMousemoveイベントに結びつけることができ、オフに行くことができることを理解しています。しかし、実際には、最大10の異なるオーバーラップコントロールがある可能性があり、私のテストアプリでは、Mousemoveイベントは、カーソルが実際のフォーム自体にある場合にのみ発射されます。
設計時に子供のコントロールが不明な場合、このイベントの処理方法を知っていますか?
簡単に使用できる簡単なワンライナーはありますか?
解決
IMHOここには少しバイナリの状況があります。そして、「ワンライナー」はありません。私が見ることができる唯一の解決策は、イベントを実装しないコントロールを.NETコンテナに実装しないことです。
コントロールがクリックされると、通常の予想される動作は、フォームのアクティブコントロールになることです(これは常にthis.activcecontrolでアクセスできます)。
しかし、クリックしたコントロールがマウスをキャプチャする場合、.NETがイベント「バブル」を実装していないため、何かがイベントを提起する必要があります(WPFがそうであるように)。
シールされたオブジェクトの拡張動作または拡張メソッドを作成するものを拡張する通常の方法であり、コントロールのための拡張機能を非常に簡単に書くことがわかりましたが、この場合にそれがあなたに役立つかどうかはわかりません。残念ながら、私は今母国から出ていて、遊ぶためのビジュアルスタジオがありません。
フォーム上の特定のポイントがコントロールの境界内にあるかどうかを判断するために使用できる戦略の1つは、フォームControl.Collection(this.Controls)のすべてを介してフォーム上のすべてのコントロールの領域(境界)を列挙することです。ただし、コントロールが重複している場合は、特定のポイントを含む可能性のある複数のコントロールの問題があります。
ベスト、ビル
他のヒント
これを試して:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AddMouseMoveHandler(this);
}
private void AddMouseMoveHandler(Control c)
{
c.MouseMove += MouseMoveHandler;
if(c.Controls.Count>0)
{
foreach (Control ct in c.Controls)
AddMouseMoveHandler(ct);
}
}
private void MouseMoveHandler(object sender, MouseEventArgs e)
{
lblXY.Text = string.Format("X: {0}, Y:{1}", e.X, e.Y);
}
}
私はこの投稿が非常に古いことを知っていますが、最も簡単な方法はフォームが実装されることだと思われます IMessageFilter
. 。コンストラクター(またはin OnHandleCreated
) あなたが呼ぶ
Application.AddMessageFilter(this);
そして、あなたはあなたの実装ですべてのウィンドウのメッセージをキャッチすることができます IMessageFilter.PreFilterMessage
.
Win32 ischildメソッドにはp/invokeを使用する必要があるでしょう
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);
フォームとともに Handle
適切なメッセージを処理していることを確認するためのプロパティ。
コントロールのマウスオーバーイベントハンドラーだけを使用してみませんか?
私はパンチに少し遅れていることを知っていますが、パネルをタイトルバーとして使用するとき、今日はこれに問題がありました。テキスト、PictureBox、およびいくつかのボタンをパネル内に表示するラベルがありましたが、MouseMoveイベントをトラップする必要がありました。
私がやろうと決めたのは、これを行うために再帰的なメソッドハンドラーを実装することでした。私は1レベルのネストされたコントロールしか持っていなかったため、これは、あなたがとんでもないレベルのネストに近づき始めるときに過度にスケーリングしないかもしれません。
これが私がそれをした方法です:
protected virtual void NestedControl_Mousemove(object sender, MouseEventArgs e)
{
Control current = sender as Control;
//you will need to edit this to identify the true parent of your top-level control. As I was writing a custom UserControl, "this" was my title-bar's parent.
if (current.Parent != this)
{
// Reconstruct the args to get a correct X/Y value.
// you can ignore this if you never need to get e.X/e.Y accurately.
MouseEventArgs newArgs = new MouseEventArgs
(
e.Button,
e.Clicks,
e.X + current.Location.X,
e.Y + current.Location.Y,
e.Delta
);
NestedControl_Mousemove(current.Parent, newArgs);
}
else
{
// My "true" MouseMove handler, called at last.
TitlebarMouseMove(current, e);
}
}
//helper method to basically just ensure all the child controls subscribe to the NestedControl_MouseMove event.
protected virtual void AddNestedMouseHandler(Control root, MouseEventHandler nestedHandler)
{
root.MouseMove += new MouseEventHandler(nestedHandler);
if (root.Controls.Count > 0)
foreach (Control c in root.Controls)
AddNestedMouseHandler(c, nestedHandler);
}
そして、それをセットアップするのは比較的簡単です:
あなたの「真の」ハンドラーを定義します:
protected virtual void TitlebarMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
this.Text = string.Format("({0}, {1})", e.X, e.Y);
}
}
そして、コントロールイベントの加入者を設定します。
//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);
比較的使いやすく、私はそれが機能するという事実を保証することができます:)