Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vb.net/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Vb.net 窗体位于顶部,但在显示模式对话框时不可单击_Vb.net_Focus_Modal Dialog_Topmost_Createparams - Fatal编程技术网

Vb.net 窗体位于顶部,但在显示模式对话框时不可单击

Vb.net 窗体位于顶部,但在显示模式对话框时不可单击,vb.net,focus,modal-dialog,topmost,createparams,Vb.net,Focus,Modal Dialog,Topmost,Createparams,我想要的是一个小的通知消息,当有任何消息要显示时,它会显示在右下角。如果没有,则不会显示通知消息。通知消息不应窃取焦点或阻止主应用程序 我拥有的是一个应用程序,它将任务作为一种消息服务来运行。此应用程序包含多个作为模式对话框打开的对话框 当消息到达应用程序时,它将被添加到可观察列表中。这将以显示通知消息的形式触发eventhandler,并将其重新绘制以显示列表中的第一项。 当消息被读取/关闭时,它将从再次触发事件的列表中删除,并使用列表中第一项的信息更新表单。 如果列表为空,则表单将隐藏 我的

我想要的是一个小的通知消息,当有任何消息要显示时,它会显示在右下角。如果没有,则不会显示通知消息。通知消息不应窃取焦点或阻止主应用程序

我拥有的是一个应用程序,它将任务作为一种消息服务来运行。此应用程序包含多个作为模式对话框打开的对话框

当消息到达应用程序时,它将被添加到可观察列表中。这将以显示通知消息的形式触发eventhandler,并将其重新绘制以显示列表中的第一项。 当消息被读取/关闭时,它将从再次触发事件的列表中删除,并使用列表中第一项的信息更新表单。 如果列表为空,则表单将隐藏

我的问题是,如果我收到一条消息并显示了通知消息表单,在我关闭它之前,主应用程序中会打开一个模式对话框,我的带有通知消息的表单仍然位于所有内容的顶部,甚至是模式对话框,但它不可单击

我已经搜索和阅读了几个论坛的答案,但还没有找到答案

可以在Github上找到一个模拟这种行为的小型测试应用程序。

一些快速信息:

NotificationMessage表单具有:

  • 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=