如何在Excel interop中强制停止单元格编辑?

4
我有一个带有选项卡的Excel 2007插件。选项卡中的一个按钮会触发当前工作表的大量操作,我设置了各种 Excel.Application 属性,如 InteractiveEnableEventsfalse,以提高速度和用户体验。

我的问题是选项卡没有窃取焦点,因此如果用户在单击我的选项卡按钮时正在编辑单元格,则会抛出异常,因为Excel认为用户仍在编辑单元格。

是否有一种方法可以通过保存或放弃对单元格所做的更改来停止编辑?

似乎 Range.DiscardChanges() 可以解决我的问题,但在2007 API中不可用。

编辑:似乎 Range.DiscardChanges() 是针对基于OLAP数据源的范围,因此无论如何都无法解决我的问题。

编辑:我尝试在另一个单元格上调用 Range.Activate(),虽然我在 GUI 中看到单元格焦点正在更改,但仍会抛出异常。 Range.Select() 不起作用。


这个链接底部有一个解决方案,可能会有所帮助:http://www.autoitscript.com/forum/topic/109032-excel-bug-comsolved/ - kevchadders
@kevchadders 这个解决方案在Excel中使用了第三方脚本库,我想要一个.NET解决方案。虽然似乎所有的问题都归结于发送ESC键,但是我用Application.SendKeys()并没有起作用。我感觉此时Ribbon处于焦点状态,ESC键不会影响正在编辑的单元格。 - dee-see
事实上,“SendKeys”无法工作的原因是ESC只有在执行完成并且GUI控制时才会生效。 - dee-see
如果您仍需要解决方案,我已经在您的.NET代码中找到了一个使用Interop事件处理程序的简单解决方案。 - cyberponk
6个回答

5

你无法停止编辑,但可以检查是否启用了编辑,并告诉用户停止编辑:

private bool IsEditing(Microsoft.Office.Interop.Excel.Application excelApp)
{
    if (excelApp.Interactive)
    {
        try
        {
            excelApp.Interactive = false;
            excelApp.Interactive = true;
        }
        catch (Exception)
        {
            MessageBox.Show("Please stop cell editing before you continue.");
            return true;
        }
    }
    return false;
}

我在这个页面找到了答案,并将其从VBA更改为C#: https://www.add-in-express.com/creating-addins-blog/2011/03/23/excel-check-user-edit-cell/

4

经过几天的搜索和在MSDN上询问,最终的答案是API中没有相关内容,而且没有使用hacky解决方案是不可能的1

Excel本身处理这种情况的方式是在用户编辑时将其菜单变灰,为了与主机应用程序保持一致,我也采取了这种方式。

1:hacky,因为像使用SendKeys这样的技术需要返回GUI以确保动作被处理,然后调用需要单元格不处于编辑状态的方法。这对于一个地方来说很好,但对于每个对Excel Interop的方法调用都这样做就有些疯狂了。


目前这不是真的。现在有一个简单的解决方案,可以在.NET代码中使用Interop事件处理程序。请查看我的答案。 - cyberponk

1

也许已经太晚回答了。但是当有人寻找解决方案时,考虑到某些原因,sendkeys和Cells/Range activate命令无法正常工作。

唯一的解决方法是将焦点切换到另一个工作表,然后返回当前工作表来欺骗Excel,以摆脱这个问题。:-)

ExcelUtil.ActivateWorksheet("Sheet1");
currentWorksheet.Activate();

public static void ActivateWorksheet(string strWorksheetName)
    {
        bool found = false;

        foreach (Excel.Worksheet sheet in Globals.ThisAddIn.Application.Worksheets)
        {
            if (sheet.Name.ToLower() == strWorksheetName.ToLower())
            {
                found = true;
                break;
            }
        }

        if (!found)
            Globals.ThisAddIn.AddNewWorksheet(strWorksheetName);

        ((Excel.Worksheet)Globals.ThisAddIn.Application.Worksheets[strWorksheetName]).Activate();
    }

希望这可以帮到你。

Ram


除非单元格正在被主动编辑,否则应用程序将不会响应任何方法调用。这需要使用try/except来处理。 - David Zemens

0

其他提出的解决方案都对我没用,后来我了解到我们可以在VB.NET应用程序中使用Excel事件,并使用“BeforeClose”事件创建了一个解决方案,强制Excel退出单元格编辑模式。

VB.NET代码:

'Declare Excel object'
Public WithEvents Excel As New Microsoft.Office.Interop.Excel.Application
public Fake_close as boolean

Public Function Is_in_edit_mode() As Boolean
    Try
        Excel.Interactive = Excel.Interactive
    Catch Ex As Exception
        Return True
    End Try
    Return False
End Function

Public Sub Exit_cell_edit_mode()
    If Not Is_in_edit_mode() Then Exit Sub

    'initiates closing the worksheet, which forces cancellation of cell edit mode.'
    Fake_close = True  'Signal that the closing event is fake'
    Excel.ActiveWorkbook.Close()  'This command will trigger the event below'
End Sub

'This event will be triggered in the VB.NET app before the workbook is closed on Excel'
Private Sub WorkbookBeforeClose(Wb As Workbook, ByRef Cancel As Boolean) Handles Excel.WorkbookBeforeClose
    If Fake_close Then 
        Cancel = True  'Cancel the closing of the workbook'
        Fake_close = False
    End if
End Sub

-1

如果您选择另一个单元格或所有单元格,错误是否消失?

private void myFunction() { xlSheet.Cells.Select(); //其余的工作 }


它不起作用。Range.Activate 看起来更有希望,但异常仍然被抛出。我已经将这些信息添加到问题中。 - dee-see
一个不太好的方法是 Application.SendKeys("{ESC}")。这会发送一个 ESC 键给应用程序,从而丢弃更改。但我认为这不是一个可靠的解决方案。 - CynicalSection
是的,我已经尝试过了,但正如问题评论中所述,它没有起作用。 - dee-see

-1
我检测到了问题并显示了一条消息告诉用户: 如果 excelHelper.ExcelIsEditing(),那么 System.Media.SystemSounds.Beep.Play() MsgBox("请完成表格编辑!" & vbCrLf & vbCrLf & "将光标移出当前单元格,然后再次尝试按钮。") Exit Function
函数 ExcelIsEditing() As Boolean ExcelIsEditing = False
  If ExcelApp.Interactive = False Then Return False
  Try
     ExcelApp.Interactive = False
     ExcelApp.Interactive = True
  Catch
     Return True
  End Try

结束函数

这是我能想到的最好的了 :_(


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