加载任何窗体时的运行事件 [英] Run event when any Form loads

查看:80
本文介绍了加载任何窗体时的运行事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我们的主要前端为表格创建一次流行度竞赛。有很多不再使用的物品,但是要弄清哪些物品已经使用以及哪些物品不再使用的细节非常困难。

I'm trying to create a Popularity Contest for Forms in our primary front end. There are many items that are no longer used, but getting details on which are used and which are no longer used is proving to be difficult.

所以我想出了在加载表单时记录日志,然后在一年左右的时间内进行记录的想法,我将进行分组研究,以了解使用哪种表单,使用频率以及使用对象。现在的问题是,我不想在每个窗体InitializeComponent块中添加一行。相反,我想把它放在Program.cs文件中,并介绍一些如何拦截所有Form加载,以便我可以记录它们。

So I came up with the idea of logging a form when it is loaded and then in a year or so I'll run a group by and get an idea of which forms are used, how often, and by who. Now the issue is that I don't want to add a line to every forms InitializeComponent block. Instead I would like to put this in the Program.cs file and some how intercept all Form loads so I can log them.

这可能吗?

编辑

使用@Jimi的评论,我可以提出以下内容。

Using @Jimi's comment I was able to come up with the following.

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;
        }
    }
}

但是,我想知道是否有是一种获取表单名称而不是文本的方法。由于这正在访问所有窗口,因此位于托管空间之外,因此我对此表示怀疑。仍然有效,如果没有其他人这样做,我明天将其发布为答案。

However, I wonder if there is a way to get the name of the form instead of it's Text. Since this is accessing ALL windows and is therefor outside of the managed space, I doubt it. Still, it works and I'll post this as an answer tomorrow if no one else does so.

推荐答案

我正在发布

如图所示,此代码只需要插入 Program.cs中,即可检测和记录Forms活动所需的代码。 文件中的 Main 方法中。

I'm posting the code that is required to detect and log Forms activity, for testing or for comparison reasons.
As shown, this code only needs to be inserted in the Program.cs file, inside the Main method.

此过程记录每个新打开的窗体的标题/标题和窗体的名称。

其他元素可以添加到日志中,可能使用专用的方法。

This procedure logs each new opened Form's Title/Caption and the Form's Name.
Other elements can be added to the log, possibly using a dedicated method.

新的 WindowPattern.WindowOpenedEvent 事件检测到创建了新窗口,将 AutomationElement.ProcessId 与应用程序的ProcessId进行比较,以确定是否新窗口属于该应用程序。

When a new WindowPattern.WindowOpenedEvent event detects that a new Window is created, the AutomationElement.ProcessId is compared with the Application's ProcessId to determine whether the new Window belongs to the Application.

然后使用Application.OpenForms()集合docs.microsoft.com/zh-CN/dotnet/api/system.windows.forms.control.accessibilityobject rel = nofollow noreferrer> Form.AccessibleObject 强制转换为 Control.ControlAccessibleObject 比较 AutomationElelement。带有 Form.Handle 属性的NativeWindowHandle ,以避免调用UI线程来获取Form的句柄(该句柄可以生成异常或线程锁, (因为当时仅在加载表单)。

The Application.OpenForms() collection is then parsed, using the Form.AccessibleObject cast to Control.ControlAccessibleObject to compare the AutomationElelement.NativeWindowHandle with a Form.Handle property, to avoid Invoking the UI Thread to get the handle of a Form (which can generate exceptions or thread locks, since the Forms are just loading at that time).

using System.Diagnostics;
using System.IO;
using System.Security.Permissions;
using System.Windows.Automation;

static class Program
{
    [STAThread]
    [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.ControlAppDomain)]
    static void Main(string[] args)
    {
        Automation.AddAutomationEventHandler(
            WindowPattern.WindowOpenedEvent, AutomationElement.RootElement,
            TreeScope.Subtree, (uiElm, evt) => {
                AutomationElement element = uiElm as AutomationElement;
                if (element == null) return;
                try 
                {
                    if (element.Current.ProcessId == Process.GetCurrentProcess().Id)
                    {
                        IntPtr elmHandle = (IntPtr)element.Current.NativeWindowHandle;
                        Control form = Application.OpenForms.OfType<Control>()
                            .FirstOrDefault(f => (f.AccessibilityObject as Control.ControlAccessibleObject).Handle == elmHandle);

                        string log = $"Name: {form?.Name ?? element.Current.AutomationId} " +
                                     $"Form title: {element.Current.Name}{Environment.NewLine}";
                        File.AppendAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "formLogger.txt"), log);
                    }
                }
                catch (ElementNotAvailableException) { /* May happen when Debugging => ignore or log */ }
            });
    }
}

这篇关于加载任何窗体时的运行事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆