C# WPF中如何在Button_Click事件间传递Excel.Worksheet变量?
问题分析与解决方案
我来帮你拆解一下为什么会出现这个异常,以及怎么修复它:
问题根源
- 全局Worksheet变量初始化错误:你在类里声明的
Excel.Worksheet x = new Excel.Worksheet();是完全错误的。Office Interop的Worksheet对象不能直接通过new关键字实例化,必须从已打开的Workbook中获取(比如通过ActiveSheet或者Worksheets[index])。这就导致你的全局x从一开始就是一个无效的对象。 - 局部变量遮蔽全局变量:在
Button_Click方法里,你又声明了一个局部的Excel.Worksheet x,这会“遮蔽”掉全局的x变量——也就是说,你在这个方法里给x赋值,只是修改了局部变量,全局的x依然是那个无效的初始值。当你点击Button_Click_1或Button_Click_2时,调用Sort(x, 1)传入的是全局的无效x,自然会抛出System.InvalidCastException。 - 为什么Button_Click_0能正常运行?:因为
Button_Click_0是在方法内部完成了从打开Excel、获取有效Worksheet实例、调用排序到退出Excel的全流程,它使用的是方法内的局部x(这个x是从excel.ActiveSheet正确获取的有效实例),完全没有依赖全局变量,所以能正常执行。
修复方案
按照以下步骤修改你的代码:
- 修正全局变量声明:去掉错误的初始化,只声明变量,避免创建无效实例。
- 在Button_Click中给全局变量赋值:去掉局部变量的声明,直接给全局
x赋值,确保后续排序方法能拿到有效的Worksheet实例。 - 优化Excel资源管理:避免重复打开Excel实例,同时在程序结束时手动释放COM对象,防止Excel进程残留后台。
修正后的完整代码示例
using Microsoft.Win32; using System.IO; using System; using System.Windows; using Excel = Microsoft.Office.Interop.Excel; namespace Sorting { public partial class MainWindow : Window { int column, CounterRow; string filepath; // 修正全局变量:只声明,不初始化错误实例 Excel.Application excelApp; Excel.Workbook excelWorkbook; Excel.Worksheet x; public MainWindow() { InitializeComponent(); } private void Choose_Files_Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Multiselect = false; ofd.Filter = "All files (*.*)|*.*"; ofd.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); if (ofd.ShowDialog() == true) { ListBox_Files.Items.Clear(); filepath = ofd.FileName; ListBox_Files.Items.Add(Path.GetFileName(filepath)); } if (ListBox_Files.Items.Count != 0) ListBox_Files.IsEnabled = Otworz.IsEnabled = true; } private void Button_Click_0(object sender, RoutedEventArgs e) { // 独立测试流程,增加资源释放逻辑避免进程残留 Excel.Application excel = new Excel.Application(); excel.Visible = true; excel.DisplayAlerts = false; Excel.Workbook workbook = excel.Workbooks.Open(filepath); Excel.Worksheet worksheet = excel.ActiveSheet as Excel.Worksheet; MessageBox.Show("select column"); Sort(worksheet,1); MessageBox.Show("end"); workbook.Close(false); excel.Quit(); // 手动释放COM对象 System.Runtime.InteropServices.Marshal.ReleaseComObject(worksheet); System.Runtime.InteropServices.Marshal.ReleaseComObject(workbook); System.Runtime.InteropServices.Marshal.ReleaseComObject(excel); } private void Button_Click(object sender, RoutedEventArgs e) { excelApp = new Excel.Application(); excelApp.Visible = true; excelApp.DisplayAlerts = false; excelWorkbook = excelApp.Workbooks.Open(filepath); // 直接给全局变量x赋值,不再声明局部变量 x = excelApp.ActiveSheet as Excel.Worksheet; } private void Button_Click_1(object sender, RoutedEventArgs e) { // 增加空值判断,避免空引用异常 if(x != null) Sort(x, 1); } private void Button_Click_2(object sender, RoutedEventArgs e) { if(x != null) Sort(x, 2); } private void Sort(Excel.Worksheet excel, int info) { Excel.Range rng = excel.Application.ActiveCell; column = rng.Column; Excel.Range userRange = excel.UsedRange; CounterRow = userRange.Rows.Count; Excel.Range range = excel.Range[excel.Cells[7, 1], excel.Cells[CounterRow - 1, 8]]; if (info == 1) range.Sort(range.Columns[column], Excel.XlSortOrder.xlAscending); else if (info == 2) range.Sort(range.Columns[column], Excel.XlSortOrder.xlDescending); } // 窗口关闭时释放所有Excel资源 protected override void OnClosed(EventArgs e) { base.OnClosed(e); if (x != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(x); } if (excelWorkbook != null) { excelWorkbook.Close(false); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelWorkbook); } if (excelApp != null) { excelApp.Quit(); System.Runtime.InteropServices.Marshal.ReleaseComObject(excelApp); } } } }
内容的提问来源于stack exchange,提问作者Kuba
相关产品推荐
相关产品推荐

