/ / Formular oben, aber nicht anklickbar, wenn das modale Dialogfeld angezeigt wird - vb.net, Fokus, modales Dialogfeld, oberste Ebene, createparams

Formular oben, aber nicht anklickbar, wenn der modale Dialog angezeigt wird - vb.net, Fokus, modaler Dialog, oberster Bereich, createparams

Was ich will ist eine kleine Benachrichtigungsmeldungwird in der rechten unteren Ecke angezeigt, wenn Nachrichten angezeigt werden sollen. Wenn dies nicht der Fall ist, wird die Benachrichtigungsmeldung nicht angezeigt. Die Benachrichtigungsnachricht sollte den Fokus nicht stehlen oder die Hauptanwendung blockieren.

Was ich habe, ist eine Anwendung, die eine Aufgabe als eine Art Nachrichtendienst ausführt. Diese Anwendung enthält mehrere Dialoge, die als modale Dialoge geöffnet werden.

Wenn eine Nachricht bei der Anwendung eingeht, ist dies der Falleiner beobachtbaren Liste hinzugefügt. Dadurch wird ein Ereignishandler in dem Formular mit der Benachrichtigungsmeldung ausgelöst, und es wird neu gezeichnet, um das erste Element in der Liste anzuzeigen. Wenn eine Nachricht gelesen / geschlossen wird, wird sie aus der Liste entfernt, wodurch das Ereignis erneut ausgelöst wird, und das Formular wird mit den Informationen aus dem ersten Eintrag in der Liste aktualisiert. Wenn die Liste leer ist, wird das Formular ausgeblendet.

Mein Problem ist, wenn ich eine Nachricht bekomme und dieDas Benachrichtigungsformular wird angezeigt, und bevor ich es schließe, wird in der Hauptanwendung ein modales Dialogfeld geöffnet. Mein Formular mit der Benachrichtigungsnachricht befindet sich weiterhin im Vordergrund, auch das modale Dialogfeld, aber es ist nicht anklickbar.

Ich habe in mehreren Foren nach einer Antwort gesucht und sie gelesen, aber ich konnte keine Antwort finden.

Eine kleine Testanwendung, die dieses Verhalten simuliert, ist bei Github zu finden. https://github.com/Oneleg/NotificationMessage

Einige schnelle Infos:

Das NotificationMessage-Formular hat:

  • FormBorderStyle = Keine
  • Oben = Falsch
  • Wird mit Show () angezeigt
  • Überladungen ShowWithoutActivation ()
  • Überladen Sie CreateParams mit WS_EX_NOACTIVATE WS_EX_TOOLWINDOW WS_EX_TOPMOST

Irgendwelche Ideen, wie ich das lösen könnte?

Antworten:

1 für die Antwort № 1

Sieht aus, als würde ich meine eigene Frage beantworten können.

Die Antwort ist, die NotificationMessage als Anwendung mit ihrer eigenen Nachrichtenpumpe zu erstellen.

Application.Run(New NotificationMessage(_messageList))

Nach einigen Änderungen sieht mein Main jetzt so aus:

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

Und die Benachrichtigungsnachricht sieht folgendermaßen aus:

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

Ich habe jetzt nur eine BenachrichtigungsnachrichtIst sichtbar, wenn Nachrichten angezeigt werden, stiehlt der Fokus nicht, wenn eine neue Nachricht eingeht. Er ist immer im Vordergrund und kann angeklickt werden, selbst wenn ein modales Formular in der Hauptanwendung geöffnet wird.