线程事件无法正确触发

时间:2018-12-12 14:50:02

标签: c# excel multithreading events

我有一个表单应用程序,可以在用户的​​Excel实例中执行操作。有时,对于较长的细分受众群,我会显示加载飞溅,这样用户就不会疯狂点击。当前,用户使用已从自定义Excel选项卡打开的表单进行操作,该表单的顶部是splashform,但是当用户最小化Excel实例(或使例如浏览器成为焦点)时,splashform仍保留在一切。

我想让线程注意到Excel是否不再处于焦点状态(隐藏启动画面),并在它获取焦点时发出通知以再次显示它。当前的实现方式非常不一致:仅在初始表单已终止后才触发hide / unhide事件。

这是当前代码;请注意,我使用线程的经验很少,因此下面可能有一些琐碎的问题。

public partial class SplashForm : Form
{
    // delegates for cross-thread actions
    private delegate void HideDelegate();
    private delegate void UnhideDelegate();

    // the current instance of the splash
    private static SplashForm splashForm;

    static public void ShowSplashScreen(String message)
    {
        // the splashform displaying thread    
        Thread splashThread = new Thread(SplashForm.ShowForm);
        splashThread.IsBackground = true;
        splashThread.SetApartmentState(ApartmentState.STA);

        // the thread monitoring the focus
        Thread focusThread = new Thread(SplashForm.RunFocusMonitor);
        focusThread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.STA);

        focusThread.Start(splashThread);
        splashThread.Start(message);
    }

    static private void ShowForm(object message)
    {
        splashForm = new SplashForm();
        splashForm.Visible = true;

        // show the splashform
        Application.Run(splashForm);
    }

    static private void RunFocusMonitor(object splashThread)
    {
        // create a new instance of fm
        var fm = new FocusMonitor();
        Thread target = (Thread)splashThread;

        // keep this thread alive until while the splashform is being shown to the user
        while (target.IsAlive)
        {
            Thread.Sleep(1000);
        }

        fm = null;
    }

    static private void HideFormInternal()
    {
        splashForm.Visible = false;
    }

    static private void UnhideFormInternal()
    {
        splashForm.Visible = true;
    }
}

public class FocusMonitor
{
    public FocusMonitor()
    {
        // subcribe
        AutomationFocusChangedEventHandler focusHandler = OnFocusChanged;
        Automation.AddAutomationFocusChangedEventHandler(focusHandler);
    }

    private void OnFocusChanged(object sender, AutomationFocusChangedEventArgs e)
    {
        AutomationElement focusedElement = sender as AutomationElement;
        if (focusedElement != null)
        {
            try
            {
                int processId = focusedElement.Current.ProcessId;
                using (Process process = Process.GetProcessById(processId))
                {
                    // if the process is Excel: show the splashform
                    if(process.ProcessName == "EXCEL")
                    {
                        splashForm.Invoke(new UnhideDelegate(UnhideFormInternal));
                    }
                    else // otherwise hide it
                    {
                        splashForm.Invoke(new HideDelegate(HideFormInternal));
                    }
                }
            }
            catch { }
        }
    }
}

0 个答案:

没有答案