我有一个表单应用程序,可以在用户的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 { }
}
}
}