2010-06-09 10 views
8

Finché il mouse si trova su un controllo specifico, mostriamo una forma. Quando il mouse lascia il controllo, nascondiamo il controllo dopo un piccolo timeout. Questo è un comportamento di hover standard..NET C# MouseEntro listener su un controllo WITH Scrollbar

Tuttavia, quando un controllo (ad esempio, un Treeview) ha una barra di scorrimento, e il mouse è su o oltre la barra di scorrimento, gli eventi non sparare ...

Se siamo riusciti a ottenere un riferimento al controllo della barra di scorrimento, questo risolverebbe il nostro problema, poiché aggiungeremmo gli stessi eventi listener alla barra di scorrimento. Tuttavia, la barra di scorrimento non è accessibile per quanto ne so ...

Come possiamo risolvere questo problema?

risposta

3

La barra di scorrimento si trova in zona non-client della vista ad albero. Quando il mouse si sposta lì, inizia a generare messaggi non client come WM_NCMOUSEMOVE e WM_NCMOUSELEAVE. Dovresti eseguire la sottoclasse del controllo TreeView e sovrascrivere WndProc() per rilevare questi messaggi.

Questo non risolve il tuo problema, tuttavia, avrai ancora problemi con i casi limite. Un approccio low-tech con un timer funziona sempre:

private Form frmPopup; 

    private void treeView1_MouseEnter(object sender, EventArgs e) { 
     timer1.Enabled = true; 
     if (frmPopup == null) { 
      frmPopup = new Form2(); 
      frmPopup.StartPosition = FormStartPosition.Manual; 
      frmPopup.Location = PointToScreen(new Point(treeView1.Right + 20, treeView1.Top)); 
      frmPopup.FormClosed += (o, ea) => frmPopup = null; 
      frmPopup.Show(); 
     } 
    } 

    private void timer1_Tick(object sender, EventArgs e) { 
     Rectangle rc = treeView1.RectangleToScreen(new Rectangle(0, 0, treeView1.Width, treeView1.Height)); 
     if (!rc.Contains(Control.MousePosition)) { 
      timer1.Enabled = false; 
      if (frmPopup != null) frmPopup.Close(); 
     } 
    } 
2

Penso che ci siano diversi modi per farlo, ma la chiave è il tuo desiderio di avere un timeout sull'azione. Penso che una combinazione di due tecniche potrebbe funzionare:

Metti il ​​controllo su un pannello, agganciato per riempire, e usa il MouseEnter del pannello per attivare il tuo comportamento - questo includerà la barra di scorrimento del controllo. Puoi anche utilizzare l'evento MouseLeave del pannello, ma dovrai controllare la posizione del cursore per assicurarti che non si sia spostato nel controllo contenuto. Questo metodo è per lo più affidabile, ma muoverlo velocemente può confonderlo.

Se si combina questo con un timer che inizia quando viene mostrato il controllo mostrato/nascosto e controllare periodicamente la posizione del cursore. Questo funzionerà, ma il tuo timeout prima di nascondere il controllo non sarà necessariamente coerente (perché il timer inizia quando entrano nel controllo). È possibile interrompere/avviare il timer su mousemove nel controllo per alleggerirlo in qualche modo.

ho messo insieme un progetto dei diversi metodi che ho provato qui: http://lovethedot.s3.amazonaws.com/100609StackoverflowScrollbarQuestion.zip

Con l'attracco il controllo che si desidera tenere traccia nel pannello, si avvolge in sostanza, e si otterrà MouseEnter al limite della controllo cingolato: ingresso

private void panel1_MouseEnter(object sender, EventArgs e) 
    { 
     this.Text = "in"; 
    } 

    private void panel1_MouseLeave(object sender, EventArgs e) 
    { 
     if (!new Rectangle(new Point(0, 0), panel1.Size).Contains(panel1.PointToClient(Control.MousePosition))) 
      this.Text = "out"; 
    } 

si sta monitorando nel pannello che circonda il controllo, e l'uscita dal quel pannello a condizione che il cursore non si trova all'interno del controllo cingolato.

per ottenere una migliore "congedo" esperienza, è combinato con un timer che controlla per vedere dove si trova il cursore così:

 private void listBox3_MouseEnter(object sender, EventArgs e) 
    { 
     button1.Visible = true; 
     visibleTimer.Stop(); 
     visibleTimer.Start(); 
    } 

    void visibleTimer_Tick(object sender, EventArgs e) 
    { 
     if (!new Rectangle(new Point(0, 0), listBox3.Size).Contains(listBox3.PointToClient(Control.MousePosition))) 
     { 
      visibleTimer.Stop(); 
      button1.Visible = false; 
     } 
    } 
+0

Il contenitore del pannello è stata una grande idea, ma che non funziona perché gli eventi non ar gorgogliare ai controlli padre ... che sarebbe lo stesso come l'aggiunta di l'evento mouseenter per l'intero modulo. Il timeout e il timer non sono un problema, quelli stanno funzionando alla grande. Grazie comunque!! –