Vb.net 窗体位于顶部,但在显示模式对话框时不可单击
我想要的是一个小的通知消息,当有任何消息要显示时,它会显示在右下角。如果没有,则不会显示通知消息。通知消息不应窃取焦点或阻止主应用程序 我拥有的是一个应用程序,它将任务作为一种消息服务来运行。此应用程序包含多个作为模式对话框打开的对话框 当消息到达应用程序时,它将被添加到可观察列表中。这将以显示通知消息的形式触发eventhandler,并将其重新绘制以显示列表中的第一项。 当消息被读取/关闭时,它将从再次触发事件的列表中删除,并使用列表中第一项的信息更新表单。 如果列表为空,则表单将隐藏 我的问题是,如果我收到一条消息并显示了通知消息表单,在我关闭它之前,主应用程序中会打开一个模式对话框,我的带有通知消息的表单仍然位于所有内容的顶部,甚至是模式对话框,但它不可单击 我已经搜索和阅读了几个论坛的答案,但还没有找到答案 可以在Github上找到一个模拟这种行为的小型测试应用程序。 一些快速信息: NotificationMessage表单具有:Vb.net 窗体位于顶部,但在显示模式对话框时不可单击,vb.net,focus,modal-dialog,topmost,createparams,Vb.net,Focus,Modal Dialog,Topmost,Createparams,我想要的是一个小的通知消息,当有任何消息要显示时,它会显示在右下角。如果没有,则不会显示通知消息。通知消息不应窃取焦点或阻止主应用程序 我拥有的是一个应用程序,它将任务作为一种消息服务来运行。此应用程序包含多个作为模式对话框打开的对话框 当消息到达应用程序时,它将被添加到可观察列表中。这将以显示通知消息的形式触发eventhandler,并将其重新绘制以显示列表中的第一项。 当消息被读取/关闭时,它将从再次触发事件的列表中删除,并使用列表中第一项的信息更新表单。 如果列表为空,则表单将隐藏 我的
- FormBorderStyle=无
- 最顶端=假
- 与Show()一起显示
- 重载在未激活的情况下显示()
- 使用WS_EX_NOACTIVATE WS_EX_TOOLWINDOW WS_EX_TOPMOST重载CreateParams
有什么办法可以解决这个问题吗?看来我可以回答我自己的问题了 答案是将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
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
通知消息如下所示:
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
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
导入System.Runtime.InteropServices
公共类通知消息
Public Sub New(消息作为ObservableGenericList(字符串))
初始化组件()
_消息=消息
AddHandler\u messages.Changed,AddressOf ListChanged
端接头
私有只读消息作为ObservableGenericList(字符串)
私有委托子列表changedelegate()
私有子列表已更改()
如果需要,那么
BeginInvoke(新ListChangedDelegate(ListChanged的地址))
返回
如果结束
如果有,那么
将消息设置为字符串=\u messages.First
Text=message
lblCounter.Text=String.Format(“({0}messages)”,_messages.Count)
Show()
其他的
隐藏()
如果结束
端接头
私有子MessageLoad(发送者作为System.Object,e作为EventArgs)处理MyBase.Load
左=Screen.PrimaryScreen.WorkingArea.Width-宽度
顶部=屏幕.PrimaryScreen.WorkingArea.Height-高度
端接头
私有子btnClose\u单击(发件人作为System.Object,e作为System.EventArgs)处理btnClose。单击
_messages.RemoveFirst()
端接头
#区域“覆盖”
私有Const WS_EX_NOACTIVATE=&H8000000'不窃取焦点
Private Const WS_EX_TOOLWINDOW=&H80'使窗体从Alt+Tab窗口隐藏
Private Const WS_EX_TOPMOST=&H8'使窗口位于最顶端
''表示窗口显示时是否将被激活。
''' http://msdn.microsoft.com/en-us/library/system.windows.forms.form.showwithoutactivation.aspx
受保护的重写只读属性ShowWithoutActivation()为布尔值
得到
返回真值
结束
端属性
''重写在创建控制句柄时设置的创建参数。
受保护的将只读属性CreateParams()重写为CreateParams
得到
将参数设置为CreateParams=MyBase.CreateParams
params.ExStyle=params.ExStyle或WS_EX_noactive或WS_EX_TOOLWINDOW或WS_EX_topmest
返回参数
结束
端属性
#末端区域
末级
我现在有一条通知消息,只有在有任何消息要显示时才可见,在新消息到达时不会窃取焦点,始终位于顶部,即使在主应用程序中打开模式表单后也可以单击。看起来我可以回答我自己的问题了 答案是将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
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
通知消息如下所示:
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
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
导入System.Runtime.InteropServices
公共类通知消息
Public Sub New(消息作为ObservableGenericList(字符串))
初始化组件()
_消息=消息
AddHandler\u messages.Changed,AddressOf ListChanged
端接头
私有只读消息作为ObservableGenericList(字符串)
私有委托子列表changedelegate()
私有子列表已更改()
如果需要,那么
BeginInvoke(新ListChangedDelegate(ListChanged的地址))
返回
如果结束
如果有,那么
将消息设置为字符串=\u messages.First
Text=message
lblCounter.Text=String.Format(“({0}messages)”,_messages.Count)
Show()
其他的
隐藏()
如果结束
端接头
私有子MessageLoad(发送者作为System.Object,e作为EventArgs)处理MyBase.Load
左=Screen.PrimaryScreen.WorkingArea.Width-宽度
顶部=屏幕.PrimaryScreen.WorkingArea.Height-高度
端接头
私有子btnClose\u单击(发件人作为System.Object,e作为System.EventArgs)处理btnClose。单击
_messages.RemoveFirst()
端接头
#区域“覆盖”
私有Const WS_EX_NOACTIVATE=&H8000000'不窃取焦点
私人Const WS_EX_TOOLWINDOW=