2015-07-28 119 views
4

我一直在開發一個應用程序的控制最近,發現自己被困在一個簡單的,但惱人的問題。如何顯示/隱藏鼠標懸停事件

我想提出一個具體的控制可見/不可見的,當我進入其母公司,並能夠執行的事件(例如:點擊)本控制。問題是,當我輸入我想要顯示的控件時,鼠標懸停在父項中甚至無法工作。這導致我想要顯示的控制閃爍(鼠標懸停工作 - >控制顯示 - >鼠標懸停不再工作 - >控制隱藏 - >鼠標懸停工程 - >等)。

我發現這個「解決方案」,以幫助我有一些「穩定」。

// Timer to make the control appearing properly. 
    private void Timer_Elapsed(object o, ElapsedEventArgs e) 
    { 
     try 
     { 
      ItemToHideDisplay.Visible = true; 
      var mousePoint = this.PointToClient(Cursor.Position); 
      if (mousePoint.X > this.Width || 
       mousePoint.X < 0 || 
       mousePoint.Y > this.Height || 
       mousePoint.Y < 0) 
      { 
       HideDisplayTimer.Stop(); 
       ItemToHideDisplay.Visible = false; 
       base.OnMouseLeave(e); 
      } 
     } 
     catch 
     { 
      // We don't want the application to crash... 
     } 
    } 

    protected override void OnMouseEnter(EventArgs e) 
    { 
     HideDisplayTimer.Start(); 
     base.OnMouseEnter(e); 
    } 

基本上,當我輸入對象時,定時器啓動並檢查每隔50ms,如果鼠標在父項中。如果是,則顯示控件。如果不是,則定時器停止並且控制隱藏。

This Works。好極了。但我覺得這個解決方案非常難看。

所以我的問題是:是否有另一種方法,另一種解決方案比這更漂亮?

告訴我,如果我不夠清楚:)

在此先感謝!

編輯:嘿,我想我已經找到了它自己!

關鍵是要重寫這個父控件OnMouseLeave在:

protected override void OnMouseLeave(EventArgs e) 
    { 
     var mousePoint = this.PointToClient(Cursor.Position); 
     if (mousePoint.X > this.Width || 
mousePoint.X < 0 || 
mousePoint.Y > this.Height || 
mousePoint.Y < 0) 
     { 
      base.OnMouseLeave(e); 
     } 
    } 

這樣一來,進入我所顯示的控制(進入父控件)時,不會觸發鼠標離開事件! 它的工作原理!

感謝您的回答。您可以繼續發表您的想法,我想,因爲我沒有看到很多的解決方案在那裏的互聯網:)

回答

0

您可以控制「透明」的鼠標事件上。所以鼠標事件只會通過它。

你必須寫自己的類繼承所需的控制。例如,如果您的具體控件是Label,那麼創建一個繼承Label的新類 - 您明白了。 :-)

在自己的新類,然後利用窗口消息,讓您的控制忽略鼠標事件:

protected override void WndProc(ref Message m) 
{ 
    const int WM_NCHITTEST = 0x0084; 
    const int HTTRANSPARENT = -1; 

    switch(m.Msg) 
    { 
     case WM_NCHITTEST: 
      m.Result = (IntPtr)HTTRANSPARENT; 
      break; 
     default: 
      base.WndProc(ref m); 
    } 
} 

你可以閱讀更多關於WndProc at MSDN

+0

但我想仍然能夠點擊顯示的控件。 它可以被過濾嗎? – Matthieu

+0

要麼你沒有在你的問題中這麼說,要麼就是沒有找到它。無論如何,這使得它變得更加複雜,但是這是可能的,因爲我已經做到了。我可以在幾個小時內查看我的代碼,但是您可以搜索「SetLayeredWindowAttributes」。只是要知道,你正在深入winforms挖掘...;) –

+0

我沒有說出來,對不起。儘管我找到了解決方案。你可以看看:)。感謝這一次,我相信它會在以後幫助我! – Matthieu

-1

我會在這裏做一個技巧:)我會將控制包裹到一個新的控制:)檢查了這一點。

XAML:

<UserControl MouseEnter="Border_MouseEnter" MouseLeave="UserControl_MouseLeave" Margin="100" Background="Transparent"> 
    <UserControl x:Name="ControlToHide" Background="Red"> 
     <Button Content="hi" Width="100" Height="100"/> 
    </UserControl> 
</UserControl> 

後面的代碼:

private void Border_MouseEnter(object sender, MouseEventArgs e) 
{ 
    this.ControlToHide.Visibility = System.Windows.Visibility.Hidden; 
} 

private void UserControl_MouseLeave(object sender, MouseEventArgs e) 
{ 
    this.ControlToHide.Visibility = System.Windows.Visibility.Visible;   
} 

很輕,便於和工作。享受

+2

這個問題用winforms標記。這看起來像WPF。 –

+0

ups,爲true。我很抱歉,但這個想法可以複製。 – Jarek

+0

我已經嘗試了包裝thingy(在winforms中)。有用。有時。雖然它不是很穩定。 – Matthieu

0

您可以爲您的表單註冊一個消息過濾器,並預處理表單中的mouse move事件。由於這一點,你不必覆蓋你的子控件等

message filter,一旦在父窗體中註冊,也將工作的子窗體,所以即使您的窗體的一部分被覆蓋孩子的形式,你的目標控制應該仍然出現/消失取決於鼠標的位置。

在以下示例中,表單上有一個面板,該面板內部有一個按鈕。

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

    internal void CaptureMouseMove(Point location) 
    { 
     if (panel1.RectangleToScreen(panel1.ClientRectangle).Contains(location)) 
     { 
      button1.Visible = true; 
      Console.WriteLine(location + "in " + panel1.RectangleToScreen(panel1.ClientRectangle)); 
     } 
     else 
     { 
      button1.Visible = false; 
      Console.WriteLine(location + "out " + panel1.RectangleToScreen(panel1.ClientRectangle)); 
     } 
    } 

    internal bool Form1_ProcessMouseMove(Message m) 
    { 
     Point pos = new Point(m.LParam.ToInt32() & 0xffff, m.LParam.ToInt32() >> 16); 
     Control ctr = Control.FromHandle(m.HWnd); 
     if (ctr != null) 
     { 
      pos = ctr.PointToScreen(pos); 
     } 
     else 
     { 
      pos = this.PointToScreen(pos); 
     } 
     this.CaptureMouseMove(pos); 

     return false; 
    } 

    private MouseMoveMessageFilter mouseMessageFilter; 

    protected override void OnLoad(EventArgs e) 
    { 
     base.OnLoad(e); 

     // add filter here 
     this.mouseMessageFilter = new MouseMoveMessageFilter(); 
     this.mouseMessageFilter.TargetForm = this; 
     this.mouseMessageFilter.ProcessMouseMove = this.Form1_ProcessMouseMove; 
     Application.AddMessageFilter(this.mouseMessageFilter); 
    } 

    protected override void OnClosed(EventArgs e) 
    { 
     // remove filter here 
     Application.RemoveMessageFilter(this.mouseMessageFilter); 
     base.OnClosed(e); 
    } 

    private class MouseMoveMessageFilter : IMessageFilter 
    { 
     public Form TargetForm { get; set; } 
     public Func<Message, bool> ProcessMouseMove; 

     public bool PreFilterMessage(ref Message m) 
     { 
      if (TargetForm.IsDisposed) return false; 

      //WM_MOUSEMOVE 
      if (m.Msg == 0x0200) 
      { 
       if (ProcessMouseMove != null) 
        return ProcessMouseMove(m); 
      } 

      return false; 
     } 
    } 
}