Excel 2013工作表激活

5

我有一个问题,需要在用户表单中激活工作表,相同的代码在Excel 2003到Excel 2010中运行良好,但在Excel 2013中无法正常工作。

以下是简单复现此问题的方法:

创建一个包含两个名为Sheet1Sheet2的工作表的工作簿,并在Sheet1上添加两个按钮:

  1. On click of Button1 activates Sheet2 worksheet using a Macro1 with 1 line in it:

    ThisWorkbook.Sheets("Sheet2").Select
    

    and I can edit data from it fine.

  2. On click of Button2 a UserForm1 pops up and on click of CommandButton1 call same Macro1 like this:

    Unload Me
    Macro1
    

    the Sheet2 worksheet is activated, sort of, but if I edit data in it, it actually updates corresponding cells in Sheet1, if I click on Sheet1 I can see data entered in there!

点击返回到Sheet2工作表会正确激活Sheet2工作表。

有人遇到过这样的行为吗?如果有,是否有编码解决方案可以正确激活Sheet2


你的用户窗体是模态的吗? - Eric J
是的,用户窗体是模态的。 - user2766088
我认为此时你可能有application.screenupdating = false。同时,你必须像这样调用用户窗体userform.show False。检查工作表名称,并确保有on error goto 0 - Patrick Lepelletier
9个回答

3
哇,我成功地使用2013年再现了这个错误。这是Excel新SDI界面的一个惊人的失败。有趣的是,当你按照以下步骤操作时:
- 在Sheet1上选择单元格A1 - 在Sheet2上选择单元格B2 - 单击Button2打开表格 - 单击表格上的CommandButton1(隐藏表格并激活Sheet2)
看起来像是选择了Sheet2上的单元格B2,但当你开始输入时,文本会进入Sheet1上的单元格A1;一旦按下Enter键,文本就会消失,出现在Sheet1上的单元格B2。
你几乎得亲身体验才能相信这一点。
我发现唯一可行的方法是使用Ontime函数。
Private Sub CommandButton1_Click()
    Unload Me
    'Call Macro1
    Application.OnTime Now(), "Macro1"
End Sub

我有种感觉,这并不能帮到每个人。

该句涉及IT技术相关内容。

1
请注意,同样使用SDI的Excel 2016没有这个问题,因此这个错误可能有另一个根本原因。 - OfficeAddinDev
@MathieuGuindon,我同意你的观点,Unload Me后面不应该有任何东西,但是从时间上来看,它必须在那里。我不能说我尝试过将表单实例化为对象并查看是否有任何区别。问题出在当调用表单时,它与特定的工作簿/工作表绑定,并在卸载时重新激活它。也许使用SetWindowLong hWnd,GWL_HWNDPARENT,hWndXL来更改表单的父句柄会更好,但到目前为止,我只用它来在切换工作簿/工作表时保持表单置顶。 - Profex
我只是感觉Unload Me卸载了(当前的)默认实例,然后下一个语句立即重新加载它(假设在实例方法中执行语句需要一个实例),这感觉...非常、非常不对-至少对我来说是这样。我只是讨厌[几乎]每个人都只满足于UserForm1.Show(上面的“默认实例”链接链接到我的博客文章)。 - Mathieu Guindon

2
以下是解决Excel 2013自动化激活工作表错误的方法(C#):
public static void ActivateSheetAndWorkaroundExcel2013VBASheetActivationBug( Worksheet oSheet2Activate )
{
    if( oSheet2Activate.IsNull() )
        return;

    oSheet2Activate.Activate();

    // Excel 2013 has problems activating worksheet through automation
    // https://www.google.com/webhp?ie=utf-8&oe=utf-8#q=excel+2013+worksheet+activate+problem+
    // https://dev59.com/QXbZa4cB1Zd3GeqPIrBG
    // 
    // The only way to reset the Excel 2013 state is to hide/show the active window
    if( Application.Version == "15.0" )
    {
        Window oActiveWnd = Application.ActiveWindow;
        oActiveWnd.Visible = false;
        oActiveWnd.Visible = true;
        oActiveWnd.Activate();
    }
}

请使用辅助方法而不是直接调用oSheet.Activate()。不客气:-)

2

根据Profex的回答,我能够在Excel 2013中重现错误。对于我而言解决问题的方法是将用户窗体设置为非模态。

userform1.show vbModeless

我明白如果您需要模态表单,这种解决方法可能不太有用,但希望它可以为下一个人节省一些时间。


1
我发现了一个类似情况的可能解决方法。我们有一个复杂的Excel插件,使用了COM和XLL代码(没有VBA)。我们遇到了与上述类似的问题。(从模态对话框激活工作表时,新单元格数据出现在前一个工作表上)。
在我们的情况下,我们发现只有当我们的代码评估单元格范围的“.HasFormula”属性时才会出现问题。这没有逻辑上的解释。如果我们的编译后的.Net代码评估该属性,我们会观察到该错误。如果代码忽略该属性,则不会观察到该错误。我们还发现,如果我们手动在工作表之间来回点击,该错误会消失。

我这里也遇到了同样的问题,关于是否具有公式(HasFormula)。如果我把那一行注释掉,那么OP中描述的问题就消失了。干得好,真是个好侦探! - OfficeAddinDev
此外,这个错误似乎已经在Excel 2016中得到了修复。 - OfficeAddinDev
1
继续跟进,这个HasFormula(和HasArray)问题似乎与Microsoft在2015年9月8日发布的更新KB3085502中的一个错误有关。以下链接中对该错误的描述类似于OP中描述的问题,但由于时间差异显然不能相关:http://answers.microsoft.com/en-us/office/forum/office_2013_release-office_install/microsoft-update-excel-2013-kb3085502-32-bit/0cc7d498-92cb-4478-9554-77cff286c847?page=1 - OfficeAddinDev

0
Sub Macro1()
Sheets("Sheet2").Select
End Sub

Sub Macro2()
Unload Me
Call Macro1
End Sub

这个可以运行。我能够在一定程度上重现您的错误,但可能是您的宏的位置问题?(模块与工作表)。

编辑:一开始我没有看到您的评论,我的 Excel 版本是2010年(这就是为什么我无法真正重现它)。-抱歉


0
请避免使用 .SELECT。您可能想看看 这个
话虽如此,如果您真的想要激活该工作表,请使用 .ACTIVATE。
例如:
Sheets("Sheet2").Activate

因此,在您的代码中使用它,它将看起来像这样。

Sub Macro1()
    Sheets("Sheet2").Activate
End Sub

Sub Macro2()
    Macro1
    Unload Me
End Sub

谢谢,Siddharth。我没有提到,但我也尝试了Activate,结果相同,在2013年不起作用,对于旧版本的Excel(尝试了2003、2007和2010)运行良好。 - user2766088

0

我认为Dima Reznikov的答案是正确的。我用了他的C#代码,并且在VBA中实现,看起来解决了这个问题。我的个人代码还包括使用模态UserForm。

示例:

Sub Macro1()
    Dim ws As Worksheet
    Dim win As Window

    '... bunch of code here...

    ws.Activate
    Set win = Application.ActiveWindow
    win.Visible = False
    win.Visible = True
End Sub

希望这能帮助其他被C#代码搞糊涂的人。

-1
在工作表代码中的 worksheet_selectionchange 事件中,只需输入 me.activate 即可。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Me.Select
End Sub

-1

我有同样的问题,但我的代码实际上是在Excel COM插件中运行的,与VBA略有不同。

我的代码在2003、2010年使用Sheets("Sheet2").Activate时可以正常工作,但在2013年就不行了。

但我通过在事件代码(Button事件)后100毫秒启动计时器来解决了这个问题。

然后这个计时器打开文件并使用Sheets("Sheet2").Activate。它被选择,就像在旧版本中一样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接