C# Excel自动化:缺少关闭事件
又一个大家好 我正在通过C#中的互操作实现Excel自动化,我希望在工作簿关闭时收到通知。但是,工作簿上没有关闭事件,应用程序上也没有退出事件 以前有人这样做过吗如何编写一段代码来对关闭的工作簿做出反应(仅当工作簿确实关闭时才执行)?理想情况下,这应该在关闭工作簿后发生,因此我可以依靠文件来反映所有更改 到目前为止我发现的详细信息: 存在BeforeClose()事件,但如果存在未保存的更改,则在询问用户是否保存更改之前会引发此事件,因此目前我可以处理该事件,我没有最终文件,也无法释放COM对象,这两件事都是我需要做的。我甚至不知道工作簿是否真的会关闭,因为用户可能会选择中止关闭C# Excel自动化:缺少关闭事件,c#,excel,events,interop,C#,Excel,Events,Interop,又一个大家好 我正在通过C#中的互操作实现Excel自动化,我希望在工作簿关闭时收到通知。但是,工作簿上没有关闭事件,应用程序上也没有退出事件 以前有人这样做过吗如何编写一段代码来对关闭的工作簿做出反应(仅当工作簿确实关闭时才执行)?理想情况下,这应该在关闭工作簿后发生,因此我可以依靠文件来反映所有更改 到目前为止我发现的详细信息: 存在BeforeClose()事件,但如果存在未保存的更改,则在询问用户是否保存更改之前会引发此事件,因此目前我可以处理该事件,我没有最终文件,也无法释放COM对象
然后是BeforeSave()事件。因此,如果用户选择“是”保存未保存的更改,那么BeforeSave()将在BeforeClose()之后执行。但是,如果用户选择“中止”,然后点击“文件->保存”,则执行完全相同的事件顺序。此外,如果用户选择“否”,则根本不会执行BeforeSave()。只要用户不单击这些选项中的任何一个,同样适用。您可以同时使用这两个事件吗?在BeforeClose()上设置一个标志,然后在BeforeSave()上查看是否设置了该标志。不过,如果触发了BeforeClose()而未触发BeforeSave(),则需要一种重置方法。我不确定是否还有其他办法可以帮上忙
编辑:看起来您已经用“事件的执行顺序完全相同”来说明这一点。但是,如果你能找到一种方法来重置它(另一个“取消”事件?),它可能会工作。我使用类似轮询的方法创建了一个黑客程序,它可以工作: 给定要观察的工作簿,我创建了一个线程,定期尝试在工作簿集合中查找该工作簿 (DisposableCom类是我当前的解决方案。)
Excel.Application app=wbWorkbook.Application;
字符串sWorkbookName=wbWorkbook.Name;
线程=新线程(新线程开始(
代表()
{
bool bOpened=错误;
Excel.Workbooks wbsWorkbooks=app.Workbooks;
使用(新的DisposableCom(wbsWorkbooks))
{
while(true)
{
睡眠(1000);
if(wbsWorkbooks.ContainsWorkbookProperly(sWorkbookName))
bOpened=真;
其他的
如果(已打开)
//工作簿已打开,因此已关闭。
打破
其他的
{
//工作簿未完全打开,请不要执行任何操作
}
}
//工作簿已关闭
在工作簿关闭()后运行代码以删除;
}
}));
检查WorkbooksThread.Start();
“ContainsworkBookProperty”扩展方法如下所示:
public static bool ContainsWorkbookProperly(this Excel.Workbooks excelWbs,
string sWorkbookName)
{
Excel.Workbook wbTemp = null;
try
wbTemp = excelWbs.Item(sWorkbookName);
catch (Exception)
{
// ignore
}
if (wbTemp != null)
{
new DisposableCom<Excel.Workbook>(wbTemp).Dispose();
return true;
}
return false;
}
public static bool正确地包含了SWORKBOOK(此Excel.Workbooks excelWbs,
弦剑书)
{
Excel.Workbook wbTemp=null;
尝试
wbTemp=excelWbs.项目(剑书名称);
捕获(例外)
{
//忽略
}
如果(wbTemp!=null)
{
新的DisposableCom(wbTemp.Dispose();
返回true;
}
返回false;
}
不过,如果有更简单或更好的解决方案,我还是会感兴趣。这不是我的代码,但这对我来说很有用: 复制粘贴:
using System;
using Excel = Microsoft.Office.Interop.Excel;
namespace Helpers.Vsto
{
public sealed class WorkbookClosedMonitor
{
internal class CloseRequestInfo
{
public CloseRequestInfo(string name, int count)
{
this.WorkbookName = name;
this.WorkbookCount = count;
}
public string WorkbookName { get; set; }
public int WorkbookCount { get; set; }
}
public WorkbookClosedMonitor(Excel.Application application)
{
if (application == null)
{
throw new ArgumentNullException("application");
}
this.Application = application;
this.Application.WorkbookActivate += Application_WorkbookActivate;
this.Application.WorkbookBeforeClose += Application_WorkbookBeforeClose;
this.Application.WorkbookDeactivate += Application_WorkbookDeactivate;
}
public event EventHandler<WorkbookClosedEventArgs> WorkbookClosed;
public Excel.Application Application { get; private set; }
private CloseRequestInfo PendingRequest { get; set; }
private void Application_WorkbookDeactivate(Excel.Workbook wb)
{
if (this.Application.Workbooks.Count == 1)
{
// With only one workbook available deactivating means it will be closed
this.PendingRequest = null;
this.OnWorkbookClosed(new WorkbookClosedEventArgs(wb.Name));
}
}
private void Application_WorkbookBeforeClose(Excel.Workbook wb, ref bool cancel)
{
if (!cancel)
{
this.PendingRequest = new CloseRequestInfo(
wb.Name,
this.Application.Workbooks.Count);
}
}
private void Application_WorkbookActivate(Excel.Workbook wb)
{
// A workbook was closed if a request is pending and the workbook count decreased
bool wasWorkbookClosed = true
&& this.PendingRequest != null
&& this.Application.Workbooks.Count < this.PendingRequest.WorkbookCount;
if (wasWorkbookClosed)
{
var args = new WorkbookClosedEventArgs(this.PendingRequest.WorkbookName);
this.PendingRequest = null;
this.OnWorkbookClosed(args);
}
else
{
this.PendingRequest = null;
}
}
private void OnWorkbookClosed(WorkbookClosedEventArgs e)
{
var handler = this.WorkbookClosed;
if (handler != null)
{
handler(this, e);
}
}
}
public sealed class WorkbookClosedEventArgs : EventArgs
{
internal WorkbookClosedEventArgs(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
}
使用系统;
使用Excel=Microsoft.Office.Interop.Excel;
命名空间帮助程序.Vsto
{
公共密封类工作簿关闭监视器
{
内部类CloseRequestInfo
{
public CloseRequestInfo(字符串名称、整数计数)
{
this.WorkbookName=名称;
this.WorkbookCount=计数;
}
公共字符串工作簿名{get;set;}
公共int工作簿计数{get;set;}
}
公用工作簿关闭监视器(Excel.Application)
{
if(应用程序==null)
{
抛出新的ArgumentNullException(“应用程序”);
}
这个应用程序=应用程序;
this.Application.WorkbookActivate+=应用程序\u WorkbookActivate;
this.Application.WorkbookBeforeClose+=应用程序\u WorkbookBeforeClose;
this.Application.WorkbookDeactivate+=应用程序\u WorkbookDeactivate;
}
公共事件事件处理程序工作簿已关闭;
public Excel.Application应用程序{get;private set;}
私有CloseRequestInfo PendingRequest{get;set;}
私有作废应用程序\u工作簿停用(Excel.Workbook wb)
{
if(this.Application.Workbooks.Count==1)
{
//只有一个工作簿可用,停用意味着它将被关闭
this.PendingRequest=null;
this.OnWorkbookClosed(新的WorkbookClosedEventArgs(wb.Name));
}
}
关闭前专用作废应用程序\u工作簿(Excel.Workbook wb,ref bool cancel)
{
如果(!取消)
{
this.PendingRequest=新建CloseRequestInfo(
世界银行名称,
这是(应用程序、工作簿、计数);
}
}
专用作废应用程序\u工作簿激活(Excel.Workbook wb)
{
//如果请求挂起且工作簿计数减少,则工作簿已关闭
bool wasWorkbookClosed=true
&&this.PendingRequest!=null
&&this.Application.Workbooks.Countusing System;
using Excel = Microsoft.Office.Interop.Excel;
namespace Helpers.Vsto
{
public sealed class WorkbookClosedMonitor
{
internal class CloseRequestInfo
{
public CloseRequestInfo(string name, int count)
{
this.WorkbookName = name;
this.WorkbookCount = count;
}
public string WorkbookName { get; set; }
public int WorkbookCount { get; set; }
}
public WorkbookClosedMonitor(Excel.Application application)
{
if (application == null)
{
throw new ArgumentNullException("application");
}
this.Application = application;
this.Application.WorkbookActivate += Application_WorkbookActivate;
this.Application.WorkbookBeforeClose += Application_WorkbookBeforeClose;
this.Application.WorkbookDeactivate += Application_WorkbookDeactivate;
}
public event EventHandler<WorkbookClosedEventArgs> WorkbookClosed;
public Excel.Application Application { get; private set; }
private CloseRequestInfo PendingRequest { get; set; }
private void Application_WorkbookDeactivate(Excel.Workbook wb)
{
if (this.Application.Workbooks.Count == 1)
{
// With only one workbook available deactivating means it will be closed
this.PendingRequest = null;
this.OnWorkbookClosed(new WorkbookClosedEventArgs(wb.Name));
}
}
private void Application_WorkbookBeforeClose(Excel.Workbook wb, ref bool cancel)
{
if (!cancel)
{
this.PendingRequest = new CloseRequestInfo(
wb.Name,
this.Application.Workbooks.Count);
}
}
private void Application_WorkbookActivate(Excel.Workbook wb)
{
// A workbook was closed if a request is pending and the workbook count decreased
bool wasWorkbookClosed = true
&& this.PendingRequest != null
&& this.Application.Workbooks.Count < this.PendingRequest.WorkbookCount;
if (wasWorkbookClosed)
{
var args = new WorkbookClosedEventArgs(this.PendingRequest.WorkbookName);
this.PendingRequest = null;
this.OnWorkbookClosed(args);
}
else
{
this.PendingRequest = null;
}
}
private void OnWorkbookClosed(WorkbookClosedEventArgs e)
{
var handler = this.WorkbookClosed;
if (handler != null)
{
handler(this, e);
}
}
}
public sealed class WorkbookClosedEventArgs : EventArgs
{
internal WorkbookClosedEventArgs(string name)
{
this.Name = name;
}
public string Name { get; private set; }
}
}
// put a syncContext instance somewhere you can reach it
static SynchronizationContext syncContext = SynchronizationContext.Current ?? new System.Windows.Forms.WindowsFormsSynchronizationContext();
// subscribe to workbook deactivate
workbook.Deactivate += workbook_Deactivate;
[DebuggerHidden]
private void workbook_Deactivate()
{
// here, the workbook is still alive, but we can schedule
// an action via the SyncContext which will execute
// right after the deactivate event is completed. At that
// point, the workbook instance (RCW) will no longer be usable
// meaning that the workbook has been closed
syncContext.Post(x =>
{
try
{
// will throw if workbook is gone
workbook.Path.ToString();
}
catch
{
// handle workbook closed
}
}, null);
}