Domanda

Sto cercando di gestire un evento mouseclick su una forma particolare che dovrebbe sparare se il cursore del mouse cade tra un insieme di coordinate: diciamo un quadrato.

Capisco che se avessi una forma vuota avrei potuto semplicemente legare all'evento MouseMove e vado. Ma in realtà potrebbero esserci fino a 10 diversi controlli sovrapposti e nella mia app di test l'evento MouseMove si accende solo se il cursore è nella forma effettiva stessa e non se è un controllo su un bambino.

Qualcuno sa come gestire questo evento quando ci sono un numero sconosciuto di controlli per bambini al momento della progettazione?

C'è un semplice liner che posso usare?

È stato utile?

Soluzione

Quando qualsiasi controllo ottiene un clic, il normale comportamento previsto è che diventerà il controllo attivo del modulo (a cui è sempre possibile accedere da questo.ActivceControl).

Ma, particolarmente se il controllo che hai fatto clic su cattura il mouse, qualcosa deve sollevare un evento poiché .NET non implementa l'evento "gorgogliante" (come fa WPF).

Il solito modo di affrontare il comportamento esteso di qualsiasi oggetto sigillato o qualunque cosa sia per scrivere un metodo di estensione, e ho scoperto che la scrittura di estensioni per il controllo è abbastanza facile, ma non so se questo ti aiuterà in questo caso. Sfortunatamente sono fuori dal mio paese d'origine in questo momento e non ho Visual Studio con cui giocare.

Una strategia che puoi utilizzare per determinare se un determinato punto su una forma rientra nei limiti di qualsiasi controllo è quella di elencare le aree (limiti) di tutti i controlli sulla forma tramite 'per tutto il controllo delle forme. Colection (this.Controls). Ma, se hai controlli sovrapposti, hai il problema di più di un controllo che eventualmente contenente un determinato punto.

Migliore, Bill

Altri suggerimenti

prova questo:

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);
    }
}

So che questo post è piuttosto vecchio, ma mi sembra che il metodo più semplice sarebbe quello di implementare il modulo IMessageFilter. Nel costruttore (o in OnHandleCreated) chiami

Application.AddMessageFilter(this);

E poi puoi catturare i messaggi di tutte le finestre nell'implementazione di IMessageFilter.PreFilterMessage.

Probabilmente dovresti usare p/invocare per il metodo win32 ischild

[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);

Insieme alla forma Handle Proprietà per assicurarti di gestire i messaggi giusti.

Perché non usi solo i gestori di eventi MouseOver dei controlli?

So di essere un po 'in ritardo al pugno, ma ho avuto problemi con questo oggi quando ho usato un pannello come barra del titolo. Avevo un'etichetta per visualizzare un po 'di testo, una foto e alcuni pulsanti tutti nidificati all'interno del pannello, ma avevo bisogno di intrappolare l'evento MouseMove a prescindere.

Quello che ho deciso di fare è stato implementare un gestore di metodi ricorsivi per farlo, dato che avevo solo 1 livello di controlli nidificati, questo potrebbe non ridimensionare eccessivamente quando inizi ad avvicinarti a livelli ridicoli di nidificazione.

Ecco come l'ho fatto:

    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);
    }

E poi per configurarlo è relativamente semplice:

Definisci il tuo gestore "vero":

    protected virtual void TitlebarMouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            this.Text = string.Format("({0}, {1})", e.X, e.Y);
        }
    }

E quindi impostare gli abbonati dell'evento controlli:

//pnlDisplay is my title bar panel.
AddNestedMouseHandler(pnlDisplay, NestedControl_Mousemove);

Relativamente semplice da usare e posso garantire il fatto che funziona :)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top