2012-11-22 47 views
1

我想要的是當有任何消息要顯示時,顯示在右下角的小通知消息。如果沒有通知消息將不會顯示。通知消息不應該聚焦或阻止主應用程序。當顯示模式對話框時顯示在頂部但不可點擊

我所擁有的是一個運行任務作爲一種消息服務的應用程序。此應用程序包含多個對話框,可以打開爲模態對話框。

當消息到達應用程序時,它被添加到可觀察列表中。這將觸發表單中顯示通知消息的事件處理程序,並重新繪製它以顯示列表中的第一項。 當讀取/關閉消息時,將從列表中刪除,再次觸發事件,並使用列表中第一項的信息更新表單。 如果列表爲空,表單將被隱藏。

我的問題是,如果我收到一條消息,並且顯示通知消息窗體,並且在關閉它之前在主應用程序中打開一個模式對話框,那麼帶有通知消息的窗體仍然處於頂部,甚至模式對話框,但它不可點擊。

我已經搜索並閱讀了幾個論壇的答案,但一直沒有能夠拿出一個答案。

模擬此行爲的小型測試應用程序可以在Github上找到。 https://github.com/Oneleg/NotificationMessage

一些快速的信息:

的NotificationMessage形式有:

  • FormBorderStyle =無
  • 朵蒙特=假
  • 被顯示爲展()
  • 重載ShowWithoutActivation()
  • 重載CreateParams與WS_EX_NOACTIVATE WS_EX_TOOLWINDOW WS_EX_TOPMOST

關於如何解決此問題的任何想法?

回答

1

看起來我可以回答我自己的問題。

答案是將NotificationMessage創建爲具有自己的messagepump的應用程序。

Application.Run(New NotificationMessage(_messageList)) 

一些修改後,我的主,現在看起來是這樣的:

Imports System.Threading 
Imports System.Threading.Tasks 

Public Class frmMain 

    Private _notificationMessage As NotificationMessage 
    Private _task As Task 
    Private _messageList As ObservableGenericList(Of String) = New ObservableGenericList(Of String) 
    Private ReadOnly _cancelMessages As CancellationTokenSource = New CancellationTokenSource() 

    Private Sub btnModal_Click(sender As System.Object, e As System.EventArgs) Handles btnModal.Click 
     frmModal.ShowDialog() 
    End Sub 

    Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
     AddHandler _messageList.Changed, AddressOf MessageListChanged 
    End Sub 

    Private Sub NotificationMessageLoop(mess As String) 
     _notificationMessage = New NotificationMessage(_messageList) 
     _messageList.Add(mess) 
     Application.Run(_notificationMessage) 
    End Sub 

    Private Sub btnMessage_Click(sender As System.Object, e As System.EventArgs) Handles btnMessage.Click 

     Dim newMessage = String.Format("Message no {0}", _messageList.Count + 1) 

     If _task Is Nothing Then 
      _task = Task.Factory.StartNew(Sub() NotificationMessageLoop(newMessage), _cancelMessages.Token) 
     Else 
      _messageList.Add(newMessage) 
     End If 
    End Sub 

    Private Sub MessageListChanged() 
     If Not _messageList.Any Then 
      _cancelMessages.Cancel() 
     End If 
    End Sub 
End Class 

而且NotificationMessage看起來是這樣的:

Imports System.Runtime.InteropServices 

Public Class NotificationMessage 
    Public Sub New(messages As ObservableGenericList(Of String)) 

     InitializeComponent() 
     _messages = messages 
     AddHandler _messages.Changed, AddressOf ListChanged 

    End Sub 

    Private ReadOnly _messages As ObservableGenericList(Of String) 
    Private Delegate Sub ListChangedDelegate() 

    Private Sub ListChanged() 
     If InvokeRequired Then 
      BeginInvoke(New ListChangedDelegate(AddressOf ListChanged)) 
      Return 
     End If 

     If _messages.Any Then 
      Dim message As String = _messages.First 
      txtMessage.Text = message 
      lblCounter.Text = String.Format("({0} messages)", _messages.Count) 
      Show() 
     Else 
      Hide() 
     End If 
    End Sub 

    Private Sub MessageLoad(sender As System.Object, e As EventArgs) Handles MyBase.Load 
     Left = Screen.PrimaryScreen.WorkingArea.Width - Width 
     Top = Screen.PrimaryScreen.WorkingArea.Height - Height 
    End Sub 

    Private Sub btnClose_Click(sender As System.Object, e As System.EventArgs) Handles btnClose.Click 
     _messages.RemoveFirst() 
    End Sub 

#Region "Overrides" 

    Private Const WS_EX_NOACTIVATE = &H8000000 ' Do not steal focus 
    Private Const WS_EX_TOOLWINDOW = &H80 ' Makes form hidden from Alt + Tab window 
    Private Const WS_EX_TOPMOST = &H8 ' Makes window topmost 

    ''' <summary> Indicates whether the window will be activated when it is shown. </summary> 
    ''' <remarks> http://msdn.microsoft.com/en-us/library/system.windows.forms.form.showwithoutactivation.aspx </remarks> 
    Protected Overrides ReadOnly Property ShowWithoutActivation() As Boolean 
     Get 
      Return True 
     End Get 
    End Property 

    ''' <summary> Override for creation parameters that are set when control handle is created. </summary> 
    Protected Overrides ReadOnly Property CreateParams() As CreateParams 
     Get 
      Dim params As CreateParams = MyBase.CreateParams 
      params.ExStyle = params.ExStyle Or WS_EX_NOACTIVATE Or WS_EX_TOOLWINDOW Or WS_EX_TOPMOST 
      Return params 
     End Get 
    End Property 

#End Region 

End Class 

我現在有一個通知消息,是唯一可見當有是否顯示任何消息,在新消息到達時不會竊取焦點,始終位於最前面,即使在主應用程序中打開模式窗體後也是可點擊的。

相關問題