【问题标题】:Update excel spreadsheet from another thread从另一个线程更新 excel 电子表格
【发布时间】:2013-11-04 22:15:06
【问题描述】:

我使用 C# 创建了 COM 服务器,我的客户可以在其中接收实时更新。 更新通常从不同的线程触发。 但我注意到当回调方法更新电子表格时 Excel 会崩溃。 有什么方法可以在 UI 线程中调用更新?

附:我知道 Excel 的 RTD 功能。但它不适合我的需要,因为我需要在一次更新中使用多个参数。

【问题讨论】:

    标签: c# multithreading excel com-server


    【解决方案1】:

    你要找的是 ISyncronizedInvoke 的 Invoke / BeginInvoke 方法

    在您的 UI 线程上,进行任意控制并保留该引用...

    从要触发更新的线程,调用该控件上的 Invoke 或 BeginInvoke(控件实现 ISyncronizedInvoke),并使用您要在 UI 线程上执行的委托...从该委托您可以调用您的 COM 服务器

    //编辑:示例代码

    using System;
    using System.Windows.Forms;
    using System.Threading;
    using Microsoft.Office.Interop.Excel;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            Thread someWorkerThread;
    
            Microsoft.Office.Interop.Excel.Application ExApp;
            Worksheet wrkSheet;
    
            public Form1()
            {
                InitializeComponent();
    
                ExApp = new Microsoft.Office.Interop.Excel.Application();
    
                ExApp.Visible = true; // or else we won't see the window
    
                var books = ExApp.Workbooks;
                var wrkBook = books.Add();
                var sheets = wrkBook.Worksheets;
                wrkSheet = sheets.get_Item(1);
    
                Marshal.ReleaseComObject(sheets);
                Marshal.ReleaseComObject(wrkBook);
                Marshal.ReleaseComObject(books);
    
                someWorkerThread = new Thread(new ParameterizedThreadStart(threadHandler));
                someWorkerThread.Start(this);
            }
    
            private void threadHandler(object obj)
            {// this will be executed on a seperate worker thread
                Control mainFrm = obj as Control;
                if (mainFrm == null)
                    throw new ArgumentException("Need to have a Control as parameter");
                for (int i = 1; i < 50;i++ )
                {
                    Thread.Sleep(2500);
                    mainFrm.Invoke(new Action<int>(doStuff), i); // this will invoke the main UI thread
                }
            }
    
            private void doStuff(int i)
            {// this will be executed on the main UI thread
                var range = wrkSheet.Range[string.Format("A{0}", i)];
                range.Value = "Hello World!";
                Marshal.ReleaseComObject(range);
            }
    
    
            #region designer stuff
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.IContainer components = null;
    
            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
            protected override void Dispose(bool disposing)
            {
                if (disposing && (components != null))
                {
                    components.Dispose();
                }
                base.Dispose(disposing);
            }
    
            #region Windows Form Designer generated code
    
            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                this.label1 = new System.Windows.Forms.Label();
                this.SuspendLayout();
                // 
                // label1
                // 
                this.label1.AutoSize = true;
                this.label1.Location = new System.Drawing.Point(76, 84);
                this.label1.Name = "label1";
                this.label1.Size = new System.Drawing.Size(149, 13);
                this.label1.TabIndex = 0;
                this.label1.Text = "I am an ordinary windows form";
                // 
                // Form1
                // 
                this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
                this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
                this.ClientSize = new System.Drawing.Size(284, 262);
                this.Controls.Add(this.label1);
                this.Name = "Form1";
                this.Text = "Form1";
                this.ResumeLayout(false);
                this.PerformLayout();
    
            }
    
            #endregion
    
            private System.Windows.Forms.Label label1;
    
            #endregion
        }
    }
    

    请注意:此示例不会清理 wrkSheet 引用和 ExApp 引用...您必须在退出应用程序之前释放它们

    【讨论】:

    • 抱歉没有得到我怎样才能到达 ISyncronizedInvoke 的实例?
    • 你的意思是创建隐藏表单吗?
    • 不......你有你的程序......我猜你的程序有一个用户可见的表单......你的调用线程将需要对该表单的引用并使用它来调用 UI 线程....需要一个例子吗?
    • 啊...这是 MS Excel - 我不确定是否实施了 ISyncronizedInvoke
    • 查看示例代码...请注意:此示例不会清理 wrkSheet 引用和 ExApp 引用...您必须在退出应用程序之前释放它们
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-06
    • 2023-03-29
    • 2017-10-12
    • 2011-12-14
    • 2012-04-02
    相关资源
    最近更新 更多