如何创建指示器判断Excel中DDE链接已完成更新?
解决DDE数据更新完成后的用户通知问题
这个问题我之前碰到过好几个类似的情况,核心坑点就是DDE的数据更新是异步执行的——你调用Application.DDETerminate的时候,后台可能还在慢悠悠地传输数据呢,所以弹窗自然会提前跳出来,根本等不到更新完成。下面给你几个经过实践验证的靠谱解决方案:
方案一:轮询DDE链接状态(最通用)
通过定期检查所有DDE链接的状态,确认它们都处于正常可用状态后再弹出通知,是兼容性最好的方法:
' 按钮点击触发的主程序 Sub UpdateDDEAndNotify() ' 执行你的DDE更新逻辑(替换成你实际的PLC应用、主题和数据项) Dim ddeChan As Integer ddeChan = Application.DDEInitiate(App:="你的PLC应用名称", Topic:="你的DDE主题") Application.DDERequest Channel:=ddeChan, Item:="需要拉取的数据项" Application.DDETerminate Channel:=ddeChan ' 启动轮询检查流程 Call CheckAllDDELinksCompleted End Sub ' 轮询检查DDE链接状态的子程序 Sub CheckAllDDELinksCompleted() Dim ddeLink As Variant Dim allLinksOK As Boolean allLinksOK = True ' 遍历 workbook 中所有DDE链接 For Each ddeLink In ThisWorkbook.LinkSources(xlDDELinks) ' 检查链接状态是否正常 If Application.LinkStatus(ddeLink) <> xlLinkStatusOK Then allLinksOK = False Exit For End If Next ddeLink If allLinksOK Then ' 所有链接更新完成,弹出通知 MsgBox "所有DDE数据已完成更新!", vbInformation, "更新完成" Else ' 未完成,100毫秒后再次检查(可根据实际传输速度调整间隔) Application.OnTime Now + TimeValue("00:00:00.1"), "CheckAllDDELinksCompleted" End If End Sub
注意:如果你的DDE链接是分散在多个工作表中的,这个方法依然有效,因为LinkSources(xlDDELinks)会返回所有DDE链接的地址。
方案二:利用DDE回调机制(高效但依赖PLC支持)
如果你的PLC DDE服务器支持回调通知(也就是数据更新完成后主动告知Excel),那这个方案是最高效的,不用轮询浪费资源:
' 模块级变量,必须声明为WithEvents才能接收回调 Dim WithEvents ddeConnection As Object ' 初始化DDE连接并设置回调 Sub InitDDEWithCallback() ' 建立DDE连接 Set ddeConnection = Application.DDEInitiate(App:="你的PLC应用名称", Topic:="你的DDE主题") ' 部分PLC需要额外设置回调触发条件,可参考PLC的DDE文档 End Sub ' 数据更新完成时触发的回调事件 Private Sub ddeConnection_OnData(ByVal Channel As Integer, ByVal Item As String, ByVal Data As String) ' 数据已更新,关闭连接并弹出通知 Application.DDETerminate Channel MsgBox "数据更新完成!", vbInformation, "更新成功" End Sub
提示:不是所有PLC都支持DDE回调,需要先查阅你的PLC设备的DDE接口文档确认。
方案三:对比数据快照(备选方案)
如果前两个方案都无法适用,你可以通过对比更新前后的数据快照来判断是否完成更新:
' 模块级变量,保存更新前的数据快照 Dim originalData As Variant ' 按钮点击触发的主程序 Sub UpdateDDEWithSnapshotCheck() ' 保存更新前的目标区域数据快照(替换成你的数据范围) originalData = Sheet1.Range("A1:C10").Value ' 执行DDE更新逻辑 Dim ddeChan As Integer ddeChan = Application.DDEInitiate(App:="你的PLC应用名称", Topic:="你的DDE主题") Application.DDERequest Channel:=ddeChan, Item:="需要拉取的数据项" Application.DDETerminate Channel:=ddeChan ' 启动数据检查流程 Call CheckDataUpdated End Sub ' 检查数据是否已更新的子程序 Sub CheckDataUpdated() Dim currentData As Variant currentData = Sheet1.Range("A1:C10").Value ' 对比当前数据和快照 Dim dataChanged As Boolean dataChanged = False Dim i As Integer, j As Integer For i = 1 To UBound(originalData, 1) For j = 1 To UBound(originalData, 2) If originalData(i, j) <> currentData(i, j) Then dataChanged = True Exit For End If Next j If dataChanged Then Exit For Next i If dataChanged Then ' 数据已更新,再等待500毫秒确保数据稳定(避免中间传输状态) Application.Wait Now + TimeValue("00:00:00.5") MsgBox "所有数据已完成更新!", vbInformation, "更新完成" Else ' 未更新,100毫秒后再次检查 Application.OnTime Now + TimeValue("00:00:00.1"), "CheckDataUpdated" End If End Sub
注意:如果你的PLC数据是周期性变化的,这个方法可能会误判,建议只在数据是一次性更新的场景下使用。
内容的提问来源于stack exchange,提问作者TL140
相关产品推荐
相关产品推荐

