从计时器子调用时,ThisWorkbook.RefreshAll不起作用

时间:2019-04-01 10:16:39

标签: excel vba runtime-error refresh

[编辑:]固定代码标签[/编辑]

我设置了一个计时器(从各种来源改编的代码)。 它调用一个子程序,其中包含行ThisWorkbook.RefreshAll 如果我通过从内部击中F5来运行子RefreshData,它可以正常工作。 如果我从Timer子程序中调用该子程序,则会收到运行时错误50290

数据包括对SQL Server数据库的各种查询。

代码:

试图添加DoEvents之后,不行。同样的错误。

Sub Timer()

Dim TimeOut As Long
'Set Timeout in minutes
TimeOut = 5

If blnTimer Then

    lngTimerID = KillTimer(0, lngTimerID)

    If lngTimerID = 0 Then

        MsgBox "Error: Timer Not Stopped"

        Exit Sub

    End If

    Debug.Print "blnTimer = False"
    blnTimer = False

Else

    lngTimerID = SetTimer(0, 0, TimeSerial(0, TimeOut, 0), AddressOf RefreshData)

    If lngTimerID = 0 Then

        MsgBox "Error: Timer Not Generated"

        Exit Sub

    End If
    Debug.Print "blnTimer = True"
    blnTimer = True

End If

Debug.Print "Timer Complete at " & Time

End Sub

Sub RefreshData()

'Refresh all data connections
ActiveWorkbook.RefreshAll

'Complete all refresh events before moving on
DoEvents

Debug.Print "Data Refreshed at " & Time

End Sub

预期结果是每5分钟将调用一次RefreshData,它将运行ThisWorkbook.RefreshAll命令并更新所有外部数据连接。

[编辑:]更新-我刚刚尝试在RefreshAll上方执行Application.CalculateFullRebuild(根据here),并且CalculateFullRebuild行上出现相同的错误代码。情节变浓了...

[编辑2]我将发布完整的解决方案,因为然后将其限制在我们的办公时间内,这对于发现该帖子的人也可能有用。感谢@EvR以获得Application.OnTime帮助! 注意:下面的代码必须在ThisWorkbook中,并且要运行的模块必须在Module1中,或者您必须将Module1更改为代码所在的位置-当然,还应将Sub的名称从RefreshData更改为Sub。开始计时器和结束计时器的子菜单如下...

[Edit3]:我忘了包括MyTime的公共变量声明-如果您不将其用作公共变量(即,在任何子例程之外),则Cancel例程(ThisWorkbook_BeforeClose)将不起作用,您将每次关闭工作簿时都会出错:它需要确切的MyTime值来取消计时器。

[Edit4]:如果计时器> = officecloses,则应为-否则,当小时为17:00时,它将设置Seconds = 0 ...并且它将不会再次运行,直到工作簿再次手动打开!下面的代码已更新。

[Edit5]:秒必须为Long类型,因为当我整夜进行求和时,整数中没有足够的内存来存储所需的大量秒数!代码已在下面更新。

[Edit6]:我刚刚发现您不能将当前时间增加23小时(考虑起来很有意义-日期回落到Excel的第一个日期)。我需要添加DateAdd(“ d”,1,MyTime)并将MyTime的初始设置更改为使用Now而不是Time(现在包括时间和日期)。是的,从那时起,我每天早晨手动打开它以查找内存错误,然后手动关闭并打开...直到今天。今天是一个全新的一天!! :D更正了以下代码。

Public Dim MyTime As Date

Sub RefreshOnTime()

Dim Delay As Integer
Dim OfficeOpens As Integer
Dim OfficeCloses As Integer
Dim Overnight As Integer
Dim DayAdvance As Integer

'Delay in seconds
Delay = 240
'hour of opening
OfficeOpens = 7
'hour of closing (24hr clock)
OfficeCloses = 17

'If in working hours
If Hour(Time) >= OfficeOpens And Hour(Time) < OfficeCloses Then
    Overnight = 0
    DayAdvance = 0
'If in the morning (e.g. auto open after scheduled reboot at 3am)
ElseIf Hour(Time) < OfficeOpens Then
    Overnight = (OfficeOpens - Hour(Time))
    DayAdvance = 0
'If after 5pm add 1 to day
'Add morning hours
ElseIf Hour(Time) >= OfficeCloses Then
    Overnight = (OfficeOpens - Hour(Time))
    DayAdvance = 1
End If

Debug.Print "Hours = " & Overnight

'Add Seconds to current time
MyTime = DateAdd("s", Delay, Now)
Debug.Print "MyTime after adding Seconds = " & MyTime

'Add DayAdvance to MyTime
MyTime = DateAdd("d", DayAdvance, MyTime)
Debug.Print "MyTime after adding DayAdvance = " & MyTime

'Add Overnight to MyTime
MyTime = DateAdd("h", Overnight, MyTime)

Debug.Print "RefreshData will run at " & MyTime

'REPLACE MODULE1 with the right module
'REPLACE RefreshData with the name of your sub
Application.OnTime MyTime, "Module1.RefreshData"

End Sub


Private Sub Workbook_BeforeClose(Cancel As Boolean)

'REPLACE MODULE1 with the right module
'REPLACE RefreshData with the name of your sub
Application.OnTime MyTime, "Thisworkbook.RefreshData", , False

End Sub


Private Sub Workbook_Open()

'Just in case you need to debug
'Uncomment these 3 lines and click "No" on workbook open
'Dim Ans As Variant
'Ans = MsgBox("Do you want to run RefreshOnTime?", vbYesNo, "Yes/No")
'If Ans = vbYes Then RefreshOnTime

RefreshOnTime

End Sub

1 个答案:

答案 0 :(得分:1)

在ThisWorkbook部分中用以下代码替换您的timer-sub:

Dim MyTime As Date

Sub RefreshOnTime()
RefreshData
MyTime = DateAdd("s", 500, Time)
Application.OnTime MyTime, "Thisworkbook.RefreshOnTime"
End Sub

Private Sub Workbook_BeforeClose(Cancel As Boolean)
Application.OnTime MyTime, "Thisworkbook.RefreshOnTime", , False
End Sub

Private Sub Workbook_Open()
RefreshOnTime
End Sub