【发布时间】:2019-09-21 03:29:56
【问题描述】:
我正在尝试在我们的主要前端创建表单人气竞赛。有许多物品不再使用,但要了解哪些已使用和哪些不再使用的详细信息被证明是困难的。
所以我想出了在加载表单时记录表单的想法,然后在一年左右的时间里我会运行一个小组,了解使用哪些表单、使用频率以及由谁使用。现在的问题是我不想在每个表单 InitializeComponent 块中添加一行。相反,我想把它放在 Program.cs 文件中,以及如何拦截所有表单加载,以便我可以记录它们。
这可能吗?
编辑
使用@Jimi 的评论,我得出以下结论。
using CrashReporterDotNET;
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Windows.Automation;
using System.Windows.Forms;
namespace Linnabary
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
//This keeps the user from opening multiple copies of the program
string[] clArgs = Environment.GetCommandLineArgs();
if (PriorProcess() != null && clArgs.Count() == 1)
{
MessageBox.Show("Another instance of the WOTC-FE application is already running.");
return;
}
//Error Reporting Engine Setup
Application.ThreadException += ApplicationThreadException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomainOnUnhandledException;
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//This is the SyncFusion License Key.
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("<Removed>");
//Popularity Contest
Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent,
AutomationElement.RootElement, TreeScope.Subtree, (UIElm, evt) =>
{
try
{
AutomationElement element = UIElm as AutomationElement;
string AppText = element.Current.Name;
if (element.Current.ProcessId == Process.GetCurrentProcess().Id)
{
Classes.Common.PopularityContest(AppText);
}
}
catch (Exception)
{
//throw;
}
});
Application.Run(new Forms.frmMain());
}
private static void CurrentDomainOnUnhandledException(object sender, UnhandledExceptionEventArgs unhandledExceptionEventArgs)
{
ReportCrash((Exception)unhandledExceptionEventArgs.ExceptionObject);
Environment.Exit(0);
}
private static void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
ReportCrash(e.Exception);
}
public static void ReportCrash(Exception exception, string developerMessage = "")
{
var reportCrash = new ReportCrash("<Removed>")
{
CaptureScreen = true,
DeveloperMessage = Environment.UserName,
ToEmail = "<Removed>"
};
reportCrash.Send(exception);
}
public static Process PriorProcess()
{
Process curr = Process.GetCurrentProcess();
Process[] procs = Process.GetProcessesByName(curr.ProcessName);
foreach (Process p in procs)
{
if ((p.Id != curr.Id) && (p.MainModule.FileName == curr.MainModule.FileName))
{
return p;
}
}
return null;
}
}
}
但是,我想知道是否有办法获取表单的名称而不是文本。由于这是访问所有窗口,因此在托管空间之外,我对此表示怀疑。尽管如此,它仍然有效,如果没有其他人这样做,我会在明天发布这个作为答案。
【问题讨论】:
-
你可能想看看 Observer 设计模式
-
您可以添加到
Program.cs和AutomationEventHandler。当即将显示任何窗口(任何窗口)时会引发此事件。您可以确定此窗口是否属于当前进程(您的应用程序),如果是,则记录它。这里有一个使用 C# 的示例:Run the current application as Single Instance and show the previous instance(第二个代码部分)正在检测相反的情况,只需删除!。 -
@Cid 我创建了一个使用 IObserver
的类,但在打开表单时它不会触发。我以前从未使用过 IObserver,所以我可能对这个不太了解。 -
@Jimi 该代码似乎更多地用于阻止程序的第二个实例运行。我看不到如何在子表单加载时触发某些内容。
-
不。该代码作为一个整体用于防止应用程序的第二个实例(以及更多)。代码的第二部分(在该代码中的表单构造函数中,在您的情况下需要移动到
sub Main),仅检测窗口何时打开并确定它是否不是当前进程的一部分。这个逻辑当然可以反过来。如果您需要示例,请告诉我。
标签: c# winforms ui-automation