如果您还没有找到解决方案,这是我为自己整理的有效方法。
private async void OnOpenWorkSheetImportCommand(object sender, ExecutedRoutedEventArgs e)
{
try
{
if (e.Parameter is IWorkSheetImportViewModel model)
{
if (WorksheetDictionaries.OfType<WorksheetDictionary>().FirstOrDefault(a => a.Header.Equals(model.Header)) is WorksheetDictionary worksheetDictionary)
{
Type officeType = Type.GetTypeFromProgID("Excel.Application", true);
if (officeType != null)
{
BeforeWorkbookDictionary = worksheetDictionary.WorkbookDictionary;
OpenInteropWorkbookDictionary(worksheetDictionary.WorkbookDictionary, worksheetDictionary, true);
}
else
{
throw new ArgumentException("Microsoft Excel is not installed!");
}
}
}
}
...
..
.
}
调用 OpenInteropWorkbookDictionary 是我设置 Microsoft.Office.Interop.Excel 的地方
private void OpenInteropWorkbookDictionary(WorkbookDictionary workbookDictionary, WorksheetDictionary worksheetDictionary, bool activateWorksheet = false)
{
if (ExcelApplication != null && ExcelApplication.Visible == true)
{
ExcelApplication.ActiveWindow.Activate();
IntPtr handler = FindWindow(null, ExcelApplication.Caption);
SetForegroundWindow(handler);
}
else
{
if (ExcelApplication != null) Marshal.FinalReleaseComObject(ExcelApplication);
if (ExcelWorkbook != null) Marshal.FinalReleaseComObject(ExcelWorkbook);
if (ExcelWorksheet != null) Marshal.FinalReleaseComObject(ExcelWorksheet);
if (ExcelWorksheets != null) Marshal.FinalReleaseComObject(ExcelWorksheets);
ExcelApplication = null;
ExcelWorkbook = null;
ExcelWorksheet = null;
ExcelWorksheets = null;
ExcelApplication = new Microsoft.Office.Interop.Excel.Application
{
Visible = true,
WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMaximized
};
ExcelApplication.WindowActivate += new Microsoft.Office.Interop.Excel.AppEvents_WindowActivateEventHandler(OnWindowActivate);
ExcelApplication.WindowDeactivate += new Microsoft.Office.Interop.Excel.AppEvents_WindowDeactivateEventHandler(OnWindowDeactivate);
ExcelApplication.WorkbookOpen += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookOpenEventHandler(OnWorkbookOpen);
ExcelApplication.WorkbookActivate += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookActivateEventHandler(OnWorkbookActivate);
ExcelApplication.WorkbookDeactivate += new Microsoft.Office.Interop.Excel.AppEvents_WorkbookDeactivateEventHandler(OnWorkbookDeactivate);
ExcelWorkbook = ExcelApplication.Workbooks.Open(BeforeWorkbookDictionary.FilePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
ExcelWorkbook.BeforeClose += new Microsoft.Office.Interop.Excel.WorkbookEvents_BeforeCloseEventHandler(OnBeforeClose);
ExcelWorkbook.AfterSave += new Microsoft.Office.Interop.Excel.WorkbookEvents_AfterSaveEventHandler(OnAfterSave);
ExcelWorkbook.BeforeSave += new Microsoft.Office.Interop.Excel.WorkbookEvents_BeforeSaveEventHandler(OnBeforeSave);
ExcelWorkbook.SheetChange += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetChangeEventHandler(OnSheetChange);
ExcelWorkbook.SheetSelectionChange += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetSelectionChangeEventHandler(OnSheetSelectionChange);
ExcelWorkbook.NewSheet += new Microsoft.Office.Interop.Excel.WorkbookEvents_NewSheetEventHandler(OnNewSheet);
ExcelWorkbook.SheetBeforeDelete += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetBeforeDeleteEventHandler(OnSheetBeforeDelete);
ExcelWorkbook.SheetActivate += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetActivateEventHandler(OnSheetActivate);
ExcelWorkbook.SheetDeactivate += new Microsoft.Office.Interop.Excel.WorkbookEvents_SheetDeactivateEventHandler(OnSheetDeactivate);
ExcelWorksheets = ExcelWorkbook.Worksheets;
}
if (activateWorksheet)
{
ExcelWorksheet = ExcelWorkbook.Sheets[worksheetDictionary.Name];
ExcelWorksheet.Activate();
}
}
注意:
- 首先调用ExcelWorkbook.BeforeClose,然后再调用ExcelApplication.WorkbookDeactivate,最后才完全关闭Excel。
- 因此,在ExcelApplication.WorkbookDeactivate中,我设置并使用Process来等待其自然终止。
- 额外信息:我使用Reactive来捕获OnClose事件。
- 重要提示:当用户关闭Workbook时,我关闭Excel!
所以在OnWorkbookDeactivate中:
private async void OnWorkbookDeactivate(Microsoft.Office.Interop.Excel.Workbook Wb)
{
try
{
ProgressController = default(ProgressDialogController);
if (ExcelApplication != null && ExcelApplication.Visible == true)
{
int excelProcessId = -1;
GetWindowThreadProcessId(new IntPtr(ExcelApplication.Hwnd), ref excelProcessId);
Process ExcelProc = Process.GetProcessById(excelProcessId);
if (ExcelProc != null)
{
ExitedEventArgs = Observable.FromEventPattern<object, EventArgs>(ExcelProc, MethodParameter.Exited);
DisposableExited = ExitedEventArgs.Subscribe(evt => OnExitedEvent(evt.Sender, evt.EventArgs));
ExcelProc.EnableRaisingEvents = true;
ProgressController = await _dialogCoordinator.ShowProgressAsync(this, string.Format("Workbook {0}", BeforeWorkbookDictionary.ExcelName), "Please wait! Processing any changes...");
ProgressController.SetIndeterminate();
ExcelApplication.Quit();
if (ExcelApplication != null) Marshal.FinalReleaseComObject(ExcelApplication);
if (ExcelWorkbook != null) Marshal.FinalReleaseComObject(ExcelWorkbook);
if (ExcelWorksheet != null) Marshal.FinalReleaseComObject(ExcelWorksheet);
if (ExcelWorksheets != null) Marshal.FinalReleaseComObject(ExcelWorksheets);
ExcelApplication = null;
ExcelWorkbook = null;
ExcelWorksheet = null;
ExcelWorksheets = null;
ExcelProc.WaitForExit();
ExcelProc.Refresh();
}
}
}
catch (Exception msg)
{
...
..
.
}
}
我在课堂上设置了一些东西,以使所有这些工作正常:
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", SetLastError = true)]
private static extern int GetWindowThreadProcessId(IntPtr hwnd, ref int lpdwProcessId);
并且:
#region RoutedEventArgs Properties
private IDisposable disposableClosingEvent;
public IDisposable DisposableClosingEvent
{
get => this.disposableClosingEvent; set => SetProperty(ref disposableClosingEvent, value, nameof(DisposableClosingEvent));
}
private IObservable<EventPattern<object, EventArgs>> exitedEventArgs;
public IObservable<EventPattern<object, EventArgs>> ExitedEventArgs
{
get => exitedEventArgs; set => SetProperty(ref exitedEventArgs, value, nameof(ExitedEventArgs));
}
private IDisposable disposableExited;
public IDisposable DisposableExited
{
get => this.disposableExited; set => SetProperty(ref disposableExited, value, nameof(DisposableExited));
}
#endregion
最后: 使用OnExitedEvent进行一些最后的处理。
private async void OnExitedEvent(object sender, EventArgs e)
{
try
{
DisposableExited.Dispose();
using (SpreadsheetDocument s = SpreadsheetDocument.Open(SelectedWorkbookDictionaryImport.FilePath, false))
{
foreach (Sheet workbookSheet in s.WorkbookPart.Workbook.Sheets)
{
if (WorkbookDictionaryImports.OfType<WorkbookDictionary>().FirstOrDefault(d => d.ExcelName.Equals(SelectedWorkbookDictionaryImport.ExcelName)) is WorkbookDictionary workbookDictionary)
{
if (workbookDictionary.WorksheetDictionaryItems.OfType<WorksheetDictionary>().FirstOrDefault(d => d.Id.Equals(workbookSheet.Id)) == null)
{
Application.Current.Dispatcher.Invoke(() =>
{
WorksheetDictionary worksheetDictionary = new WorksheetDictionary()
{
WorksheetDictionaryId = Guid.NewGuid().ToString(),
IsSelected = false,
Id = workbookSheet.Id,
SheetId = workbookSheet.SheetId,
Name = workbookSheet.Name,
Header = workbookSheet.Name,
HeaderInfo = GetSheetStateValues(workbookSheet.State),
Code = GetSheetCodeValues(workbookSheet.Name.ToString()).ToString(),
Description = BeforeWorkbookDictionary.Subject,
WorkbookDictionary = BeforeWorkbookDictionary
};
workbookDictionary.WorksheetDictionaryItems.Add(worksheetDictionary);
});
}
}
}
}
}
catch (Exception msg)
{
...
..
.
}
finally
{
if (ProgressController != null)
{
await ProgressController.CloseAsync();
ProgressController = default(ProgressDialogController);
}
}
}
希望这篇文章能帮到你和其他人,当然要根据你的处理需求进行更改。