【问题标题】:How to handle 'No' or 'Cancel' on Workbook.SaveAs overwrite confirmation?如何处理 Workbook.SaveAs 覆盖确认上的“否”或“取消”?
【发布时间】:2016-07-16 04:48:02
【问题描述】:

我希望在 VBA 脚本开始修改内容之前提示用户保存工作簿。当 SaveAs 对话框出现时,如果用户单击 Cancel 我会引发自定义错误并停止脚本。如果他们点击保存并且文件名已经存在,我希望他们被询问是否覆盖。

这是我的代码:

Function SaveCurrentWorkbook(wkbSource As Workbook, strNewFileName As String) As Variant
    If Not bolDebug Then On Error GoTo errHandler
    Dim varSaveName As Variant

SaveAsDialog:
    varSaveName = Application.GetSaveAsFilename(InitialFileName:=strNewFileName, FileFilter:="Excel Files (*.xls), *.xls")
    If varSaveName <> False Then
        wkbSource.SaveAs Filename:=varSaveName, ConflictResolution:=True, Addtomru:=True
        Set SaveCurrentWorkbook = wkbSource
    Else
        SaveCurrentWorkbook = False
        Err.Raise 11111, , "Save Canceled"
    End If

exitProc:
    Exit Function

errHandler:
    Select Case Err.Number
        Case 1004 'Clicked "No" or "Cancel" - can't differentiate
            Resume SaveAsDialog
        Case esle
            MsgBox "File not saved. Stopping script.", vbOKOnly, Err.Description
            Resume exitProc
    End select

End Function

如果他们点击“是”,它会覆盖它。如果他们单击“否”,我希望出现“另存为”对话框,以便他们可以选择新的文件名,但我得到了一个错误。如果他们单击“取消”,我希望发生错误并停止脚本。问题是我无法区分“否”和“取消”之间触发的错误。

任何建议如何处理? (请原谅错误处理的不当使用 - 已经有一段时间了。)

附:此函数由另一个过程调用,因此如果用户在 SaveAs 对话框或 ResolveConflict 对话框中单击“取消”,我希望调用过程也停止。我想我可以通过检查 SaveCurrentWorkbook 返回的内容(工作簿对象或 False)来做到这一点。

【问题讨论】:

    标签: vba excel excel-2013


    【解决方案1】:

    您可以像这样简单地创建自己的“覆盖?”问题:

    Function SaveCurrentWorkbook(wkbSource As Workbook, strNewFileName As String) As Variant
        If Not bolDebug Then On Error GoTo errHandler
        Dim varSaveName As Variant
    
    SaveAsDialog:
    
        varSaveName = Application.GetSaveAsFilename(InitialFileName:=strNewFileName, FileFilter:="Excel Files (*.xls), *.xls")
        If varSaveName <> False Then
          If Len(Dir(varSaveName)) Then 'checks if the file already exists
            Select Case MsgBox("A file named '" & varSaveName & "' already exists at this location. Do you want to replace it?", vbYesNoCancel + vbInformation)
            Case vbYes
              'want to overwrite
              Application.DisplayAlerts = False
              wkbSource.SaveAs varSaveName, ConflictResolution:=2, Addtomru:=True
              Application.DisplayAlerts = True
              Set SaveCurrentWorkbook = wkbSource
            Case vbNo
              GoTo SaveAsDialog
            Case vbCancel
              SaveCurrentWorkbook = False
              Err.Raise 11111, , "Save Canceled"
            End Select
          Else
            wkbSource.SaveAs varSaveName, ConflictResolution:=True, Addtomru:=True
            Set SaveCurrentWorkbook = wkbSource
          End If
        Else
          SaveCurrentWorkbook = False
          Err.Raise 11111, , "Save Canceled"
        End If
    
    exitProc:
        Exit Function
    
    errHandler:
        Select Case Err.Number
        Case 1004 'Clicked "No" or "Cancel" - can't differentiate
          Resume SaveAsDialog
        Case Else
          MsgBox "File not saved. Stopping script.", vbOKOnly, Err.Description
          Resume exitProc
        End Select
    
    End Function
    

    正如您所注意到的,“否”和“取消”之间没有区别(对于应用程序,因为它不会自行停止保存)。 Excel 只是自欺欺人地说:“我无法在此处保存”并在两种情况下都弹出相同的错误......所以唯一真正的解决方案是创建自己的 msgbox :(

    【讨论】:

      【解决方案2】:

      我会让 SaveCurrentWorkbook 返回 True 或 False,并使用 Msgboxes 处理保存为 strNewFileName。

      然后在调用 SaveCurrentWorkbook 的脚本中,您可以进行简单的布尔评估。

      如果 SaveCurrentWorkbook(wkbSource, "C:\...\SomeFile.xls") 那么 '做一点事 别的 '做点别的 万一
      Function SaveCurrentWorkbook(wkbSource As Workbook, strNewFileName As String) As Boolean
          Dim iResult As VbMsgBoxResult
      
          Dim varSaveName As Variant
      
          If Dir(strNewFileName) <> "" Then
              iResult = MsgBox("Press [Yes] to overwite " & strNewFileName & " or [No] to choose a new filename.", vbInformation + vbYesNo, "Save File")
          Else
              iResult = MsgBox("Press [Yes] to save as " & strNewFileName & " or [No] to choose a new filename.", vbInformation + vbYesNo, "Save File")
          End If
      
          If iResult = vbYes Then
              SaveCurrentWorkbook = True
          Else
              varSaveName = Application.GetSaveAsFilename(FileFilter:="Excel Files (*.xls), *.xls")
              If CStr(varSaveName) <> "False" Then
                  wkbSource.SaveAs Filename:=varSaveName, ConflictResolution:=True, Addtomru:=True
                  SaveCurrentWorkbook = True
              End If
          End If
      
      End Function
      

      使用 SaveAs 时不需要设置引用,因为您的原始文件已关闭(未保存)并且您的引用会自动更新为新文件。如果您使用的是 SaveCopyAs,那么您的原始文件会保持打开状态,并会制作当前文件的副本(包括任何未保存的数据)。

      请注意,在下面的测试中,当我们使用 SaveAs 时,引用会更新为 SaveAs 名称。当我们使用 SaveCopAs 时,名称不会改变,因为原始文件仍处于打开状态。

      【讨论】:

      • 我想要一个对新工作簿的引用,以便我可以继续修改它。而不是真/假,我会看看我是否可以返回 Nothing 并进行测试。
      • 我更新了我的答案,解释了为什么您不需要返回对工作簿的引用。
      • 感谢 Thomas,我能够确认这项工作,它帮助我清理了我的代码。 +1
      • 太棒了!很高兴我能提供帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-09
      • 1970-01-01
      • 2020-01-17
      • 1970-01-01
      • 2017-05-02
      • 2021-03-20
      相关资源
      最近更新 更多