简体   繁体   English

C# excel 插件 - 如何从长处理任务的事件处理程序直接更新工作表 UI

[英]C# excel add in - how to directly update sheet UI from event handler on long processing tasks

Hello_ everyone.大家好。 First apologize if the question is not ask correctly and please correct me if I am wrong.如果问题不正确,请先道歉,如果我错了,请纠正我。

I am developing excel add-in using Visual Studio 2015 .我正在使用Visual Studio 2015开发 excel 插件。 The project type is Excel 2013 and 2016 VSTO Add-in and my problem is that I want to show to users some indication that application is loading data at button click but UI is being updated when data is loaded and not before that ...项目类型是Excel 2013 和 2016 VSTO 外接程序,我的问题是我想向用户显示一些指示,表明应用程序在单击按钮时正在加载数据,但在加载数据时而不是在加载数据之前更新 UI...

For example:例如:

private void MyCustomMenuItem_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault)
        {

            Excel.Worksheet sheet = Globals.ThisAddIn.Application.ActiveWorkbook.ActiveSheet;
            Excel.Shapes shapes = sheet.Shapes;
            shapes.AddTextEffect(Office.MsoPresetTextEffect.msoTextEffect1,
                "Loading please wait ...",
                "Arial",
                16,
                Office.MsoTriState.msoFalse,
                Office.MsoTriState.msoFalse,
                10,
                10
                );

            // assume that on the following line is a long processing calculation
            Thread.Sleep(3000);
            // And the problem is that the Shape will show after 3 seconds
}

My problem is that the shape element will show after the thread is ready with its job in this case after 3 seconds.我的问题是,在这种情况下,在 3 秒后线程准备好其工作后,形状元素将显示。 If on the place of Thread.Sleep(3000) I have some code that will run 40 seconds it will show the text after 40 seconds ...如果在Thread.Sleep(3000)的地方我有一些将运行 40 秒的代码,它将在 40 秒后显示文本......

I know I'm doing something wrong and not updating the UI thread correctly ...我知道我做错了什么,没有正确更新 UI 线程......

Question: How to update UI thread before a long processing task ?问题:如何在长时间处理任务之前更新 UI 线程?

Note: I'm using Microsoft.Office.Interop.Excel namespace for interacting with the excel application.注意:我使用Microsoft.Office.Interop.Excel命名空间与 Excel 应用程序交互。

I did try to show a custom form with nothing but the text "Loading please wait" but again the form is showing after the long process ends ... Other thing that I tried is rising a custom event and trying to show something from the event handler but again no success ...我确实尝试显示一个自定义表单,除了文本“正在加载请稍候”之外什么都没有,但是在漫长的过程结束后表单再次显示......我尝试的另一件事是引发自定义事件并尝试从事件中显示某些内容处理程序,但再次没有成功......

I want to avoid using Globals.ThisAddIn.Application.StatusBar = "Loading please wait ..." method and do something more user friendly.我想避免使用Globals.ThisAddIn.Application.StatusBar = "Loading please wait ..."方法并做一些更用户友好的事情。

If someone can point me what am I doing wrong it will be great.如果有人能指出我做错了什么,那就太好了。

Thanks in advance_提前致谢_

You're UI is "freezing" because the UI thread is busy doing other things.您的 UI 正在“冻结”,因为 UI 线程正忙于做其他事情。

If you're using WPF, read this question .如果您使用 WPF,请阅读此问题

If you're using Win32 Forms, read this question .如果您使用的是 Win32 Forms,请阅读此问题

This is not a vsto or excel-interop problem.这不是vstoexcel-interop问题。 You just need to be careful with threads.你只需要小心线程。 If you want your UI to update while a long process is executing, then you'll want that process to be on a background thread.如果您希望在执行长进程时更新 UI,那么您会希望该进程位于后台线程上。 However, here are a few rules to keep in mind for your case (this is not a complete list):但是,对于您的情况,请记住以下一些规则(这不是完整列表):

  1. Don't update the UI directly from a background thread.不要直接从后台线程更新 UI。
  2. Don't modify the Excel objects from a thread other than the one from which it was created.不要从创建 Excel 对象的线程以外的线程修改 Excel 对象。

If you're wanting an older/simpler way to update the UI, check out BackgroundWorker and the ReportProgress method.如果您想要一种更旧/更简单的方式来更新 UI,请查看BackgroundWorkerReportProgress方法。 If you want to keep up with the more modern Task , check out the links above.如果您想跟上更现代的Task ,请查看上面的链接。

After some study and implementation, please post some code examples if you have any trouble.经过一些研究和实现,如果您有任何问题,请发布一些代码示例。

Hello_ friend and sorry for the late answer.你好_朋友,很抱歉回复晚了。

You were totally right and with the help of the link that you posted I succeed to complete what I was trying to do.你是完全正确的,在你发布的链接的帮助下,我成功地完成了我想要做的事情。

I am posting this answer in case someone else gets in this problem and finds this discussion.我发布此答案以防其他人遇到此问题并找到此讨论。

This is what I've did:这就是我所做的:

private void ShowLoadingTextMenuItem_Click(Office.CommandBarButton Ctrl, ref bool CancelDefault)
{
    // This part is very important because on the following call  
    // to FromCurrentSynchronizationContext() you can get an exception
    if (SynchronizationContext.Current == null)
    {
        SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
    }

    var context = TaskScheduler.FromCurrentSynchronizationContext();
    var task = new Task(() =>
    {
        // Disable excel application interactivity
        // you can avoid this and user will be able to use the UI
        // but there is the possibility to get HRESULT: 0x800AC472 Exception
        // when the long processing ends and you try to update the UI
        // which is probably coming because main UI thread is busy  
        Globals.ThisAddIn.Application.Interactive = false;

        // This is a simple class that is just showing WordArt text
        // in the middle of screen to indicate the loading process
        LoadingOverlayHelper.StartLoading();
    });

    Task continuation = task.ContinueWith(t =>
    {
        Globals.ThisAddIn.Application.StatusBar = "Doing some long processing task ...";

        // At this point you start the long processing task
        Thread.Sleep(4000);

        // And when its over remove the processing text
        LoadingOverlayHelper.StopLoading();

        Globals.ThisAddIn.Application.StatusBar = "Ready";

        Globals.ThisAddIn.Application.Interactive = true;

    }, CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, context);

    // Execute the task !
    task.Start();
}

And also I made a github repository with the code that I was playing with, so anybody can get it and play with it too - https://github.com/research-and-develop/ExcelAddInPlayground/我还使用我正在使用的代码创建了一个 github 存储库,因此任何人都可以获取并使用它 - https://github.com/research-and-develop/ExcelAddInPlayground/

Thanks谢谢

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM