Multithreading 我在尝试根据计时器滴答声事件打开窗体时遇到线程错误

Multithreading 我在尝试根据计时器滴答声事件打开窗体时遇到线程错误,multithreading,visual-studio,timer,invoke,Multithreading,Visual Studio,Timer,Invoke,我有一个运行记分表前屏幕的程序。我想有一个运行的视频广告循环,弹出一个计时器的基础上。我创建了一个单独的窗体来播放视频,并使用计时器打开窗体并播放一个视频,然后递增一个全局变量,关闭窗体,然后等待计时器重新打开窗体。当计时器试图重新打开窗体时,它给了我一个线程错误。我对这一级别的编码有点陌生,对为什么会发生这种错误以及如何修复它感到困惑。我仔细阅读了这个主题,认为我基本上理解了这个问题,但似乎找不到合适的代码来让它工作。下面是代码(VAds的全局变量),我使用调用过程解决了图片框的问题,但无法为

我有一个运行记分表前屏幕的程序。我想有一个运行的视频广告循环,弹出一个计时器的基础上。我创建了一个单独的窗体来播放视频,并使用计时器打开窗体并播放一个视频,然后递增一个全局变量,关闭窗体,然后等待计时器重新打开窗体。当计时器试图重新打开窗体时,它给了我一个线程错误。我对这一级别的编码有点陌生,对为什么会发生这种错误以及如何修复它感到困惑。我仔细阅读了这个主题,认为我基本上理解了这个问题,但似乎找不到合适的代码来让它工作。下面是代码(VAds的全局变量),我使用调用过程解决了图片框的问题,但无法为视频解决同样的问题。提前谢谢

Private Sub PlayAdVideos(sender As Object, e As EventArgs) Handles VideoAds.Click
        On Error Resume Next
        If Application.OpenForms().OfType(Of frmAds).Any Then
            frmVideoAds.Close()
            Play_Ads.Text = "Start Video Advertisement Loop"
            Exit Sub
        Else
            Play_Ads.Text = "Close Video Advertisement Loop"
            Dim Sz As Integer
            If ScreenNo.Text = "" Then
                Sz = 1
            Else
                Sz = ScreenNo.Text
            End If

            Dim screen As Screen
            screen = Screen.AllScreens(Sz)
            frmVideoAds.StartPosition = FormStartPosition.Manual
            frmVideoAds.Location = screen.Bounds.Location + New Point(0, 0)
            frmVideoAds.WindowState = FormWindowState.Maximized
            frmVideoAds.FormBorderStyle = FormBorderStyle.None
            frmVideoAds.TopMost = True
            frmVideoAds.BackColor = Color.Black
            frmVideoAds.Show()
        End If

        For Each foundFile As String In My.Computer.FileSystem.GetFiles("C:\CCHS\VideoAds\")
            VideoAdList.Items.Add(foundFile)
        Next

        If VideoAdList.Items.Count = 0 Then
            Exit Sub
        End If

        Dim TMR2 As New System.Timers.Timer()

        VideoAdNum = VideoAdList.Items.Count - 1

        TMR2.Interval = 10000 'miliseconds
        TMR2.Enabled = True
        TMR2.Start()
        AddHandler TMR2.Elapsed, AddressOf OnTimedEvent

    End Sub

    Public Sub OnTimedEvent(ByVal sender As Object, ByVal e As ElapsedEventArgs)

        If frmVideoAds.InvokeRequired Then
            If VAds = VideoAdNum Then
                VAds = 0
            Else
                VAds = VAds + 1
            End If
            frmVideoAds.Invoke(Sub() frmVideoAds.Show())
        Else
            If VAds = VideoAdNum Then
                VAds = 0
            Else
                VAds = VAds + 1
            End If
            frmVideoAds.Show()

        End If
    End Sub

System.Timers.Timer已用事件通常总是在UI线程以外的线程上触发

这意味着您必须在该方法中每次调用frmVideoAds.Show()时调用frmVideoAds.Invoke

您的else语句应该只需要添加invoke,这将使两个执行路径相同,这样您就可以更新整个过程

 Public Sub OnTimedEvent(ByVal sender As Object, ByVal e As ElapsedEventArgs)
            If VAds = VideoAdNum Then
                VAds = 0
            Else
                VAds = VAds + 1
            End If
            frmVideoAds.Invoke(Sub() frmVideoAds.Show())
    End Sub
这通常是可行的,但在某些情况下,特别是ActiveX,系统计时器需要位于单线程单元(STA)中。它默认为多线程单元(MTA)。要强制它进入STA模式,只需添加

TMR2.SynchronizingObject = Me

就在您的TM2.Start()之前。

谢谢James。我试过了,但在“frmVideoAds.InvokeRequired”行System.InvalidOperationException上仍然出现错误。用户代码HResult=-2146233079 Message=创建表单时出错。有关详细信息,请参见Exception.InnerException。错误是:无法实例化ActiveX控件“6bf52a52-394a-11d3-b153-00c04f79faa6”,因为当前线程不在单线程单元中。如果每次都需要调用,则可以完全删除If语句。将其添加到Else之后,两个执行路径将是相同的。i、 没有理由检查它是否需要一个调用,不管怎样,它都需要一个。仍然抛出一个错误。这是正确的语法吗?我只是在做一个有根据的猜测。”代码'frmVideoAds.Invoke(Sub()frmVideoAds.Show())啊,内部异常会改变它。ActiveX需要单线程单元线程。您的System.Timer默认为MTA,但您可以通过在TMR2.Start()调用之前添加TMR2.SynchronizingObject=Me将其强制为STA。先生,您太棒了。这解决了问题。谢谢你的帮助那是什么编程语言?请添加一个标签,以使其对其他人更有用。