如果我以编程方式激活另一个应用程序中的窗口,我可以检测到它失去焦点吗? [英] If I programmatically activate a window in another application, can I detect when it loses focus?

查看:129
本文介绍了如果我以编程方式激活另一个应用程序中的窗口,我可以检测到它失去焦点吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

与我一起,我是一个网络开发人员尝试WinForms应用程序。

Bear with me, I'm a web developer attempting a WinForms application.

回复时请不要评论我的应用程序的目的是练习还是不行,等等。这是我需要写的应用程序,无论好坏,我不能浪费时间解释为什么。我要求你只是回复与建议(1)是我想要做的可能(2)什么是最好的方式来完成我想做的。

When responding please do not comment on whether the purpose of my application is a "best practice" or not, etc... This is the application I need to write, for better or worse, and I cannot waste time explaining the "why". I ask that you please just reply with advice on (1) Is what I'm trying to do possible (2) What is the "best" way to accomplish what I'm trying to do.

所以,这里是我想做的:
我需要写一个WinForms应用程序,将从供应商应用程序读取数据,显示某些记录到最终用户,并允许他们选择以将记录传送到另一供应商应用程序。挂起...目标系统没有暴露apis,没有sprocs,没有提供好的插入数据的方法,除了将其输入到他们的GUI。 (相信我,一个由3个人组成的团队调查了自动化这种情况的可能性)

So, here's what I'm trying to do: I need to write a WinForms application that will read data from a vendor application, display certain records to the end user and allow them to choose to "transfer" a record to another vendor application. The hang up...the destination system exposes no apis, no sprocs, provides no "good" method for inserting data, other than typing it into their GUI. (trust me on this, a team of 3 people investigated EVERY possibility for automating this)

所以这个WinForms应用程序将使用Microsoft.VisualBasic.Interaction.AppActivate将数据直接插入到目标系统的输入窗口中的字段中。目标系统在某些字段上具有F1帮助,因此如果您将重点放在字段上并按F1,或者如果在其中一个字段中输入无效数据,则会弹出名为帮助的子窗口以提供指导中。

So this WinForms app will utilize Microsoft.VisualBasic.Interaction.AppActivate(string) and insert data directly into the fields in the input window of the destination system. The destination system has F1 help on certain fields, so if you give focus to the field and press "F1", or alternatively, if you enter invalid data in one of these fields, a child window named "Help" pops up to offer guidance.

因此,我的应用程序正在插入,使用SendKeys.SendWait(string)将数据写入此应用程序的字段,然后遇到一些无效的数据和帮助窗口弹出,我的应用程序继续写出其余的数据,但现在它正在写入帮助窗口中的1字段,因为该窗口现在有焦点。

So, my app is plugging along, using SendKeys.SendWait(string) to write data into the fields of this application and then some invalid data is encountered and the Help window pops up, and my app continues to write out the rest of the data, but now it's all being written to the 1 field in Help window because that window now has focus.

百万美元问题...

有一种方法可以从我的WinForms应用程序中检测到帮助窗口

更新

Updates

首次尝试此应用程序我使用UIAutomationClient库。我无法成功激活目标窗口并写入第一个字段。经过一天的战斗后,我不得不开始寻找替代品。

First attempt at this application I used the UIAutomationClient library. I was unable to successfully activate the target window and write to the first field. After a day fighting with it I had to start looking for alternatives.

推荐答案

我有一些工作代码的开始。我认为我已经足够了,这对其他人可能有用。

I have the start of some working code. I think I have enough that this may be useful to someone else.

我发现了一种使用UIAutomation库而不是Microsoft.VisualBasic库的方法。有很多试验和错误,但这是比我的最初几次尝试使用VisualBasic库非常slicker。

I found a way to use the UIAutomation library instead of the Microsoft.VisualBasic library. There was a lot of trial and error, but this is much "slicker" than my first few attempts using the VisualBasic library.

我使用StructureChanged事件来检测帮助窗口在此概念应用程序的先前迭代中弹出。我能够成功检测到帮助窗口弹出,但我遇到了陷入试图处理帮助窗口的外观。我仍然在我的应用程序中有事件处理程序,但由于某种原因,帮助窗口不会立即弹出,我试图强制无效的数据进入其中一个字段来测试帮助窗口的处理,没有出现帮助窗口。这不是我的问题,因为帮助窗口给我造成麻烦,但我觉得需要提到,因为这篇文章是问我如何可以检测帮助窗口的外观。

I used the StructureChanged event to detect the Help window popping up in a previous iteration of this proof of concept app. I was able to successfully detect that the Help window popped up, but I was running into snags trying to handle the appearance of the Help window. I still have the event handler in my application, but for some reason the Help window does not pop up now, I tried forcing invalid data into one of the fields to test the handling of the Help window, and the Help window did not appear. This is not an issue for me, since the Help window was causing trouble for me, but I felt that it needed to be mentioned since this post was asking how I could detect the Help window's appearance.

我使用的一些资源:

http://msdn.microsoft.com/en-us/library/ms747327%28v=vs.110%29.aspx

https://www.universalthread.com/ ViewPageArticle.aspx?ID = 199

http://msdn.microsoft.com/en-us/library/ms750582%28v=vs.110%29.aspx

http://msdn.microsoft.com/en-us/library/windows/desktop/dd318521%28v=vs.85%29.aspx

private void IncidentGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
  if ((e.RowIndex < 0) || (e.ColumnIndex < 0))
    return;

  // Grab the data object that populated the row
  Incident incident = (Incident)IncidentGridView.Rows[e.RowIndex].DataBoundItem;

  // Create a property condition with the element's type
  PropertyCondition typeCondition = new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Window);
  // Create a property condition with the element's name
  PropertyCondition nameCondition = new PropertyCondition(AutomationElement.NameProperty, "Incident");
  // Create the conjunction condition
  AndCondition andCondition = new AndCondition(typeCondition, nameCondition);
  // Ask the Desktop to find the element within its children with the given condition
  _mainWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, andCondition);

  #region Register Automation Events
  //AutomationEventHandler handler = new AutomationEventHandler(OnWindowOpened);
  //Automation.AddAutomationEventHandler(WindowPattern.WindowOpenedEvent, _mainWindow, TreeScope.Element, handler);
  Automation.AddStructureChangedEventHandler(_mainWindow, TreeScope.Children, new StructureChangedEventHandler(OnStructureChanged));
  #endregion

  // Wait for the application
  Thread.Sleep(2000);

  // Write the incident to the Incident window
  PropertyCondition idCondition = new PropertyCondition(AutomationElement.AutomationIdProperty, "3279");
  AutomationElement reportedDate = _mainWindow.FindFirst(TreeScope.Descendants, idCondition);
  InsertTextUsingUIAutomation(reportedDate, incident.ReportedDate);

  PropertyCondition idCondition2 = new PropertyCondition(AutomationElement.AutomationIdProperty, "4256");
  AutomationElement reportedTime = _mainWindow.FindFirst(TreeScope.Descendants, idCondition2);
  InsertTextUsingUIAutomation(reportedTime, incident.ReportedTime);

  PropertyCondition idCondition4 = new PropertyCondition(AutomationElement.AutomationIdProperty, "7256");
  AutomationElement status = _mainWindow.FindFirst(TreeScope.Descendants, idCondition4);
  InsertTextUsingUIAutomation(status, "WAR");

  PropertyCondition idCondition5 = new PropertyCondition(AutomationElement.AutomationIdProperty, "5404");
  AutomationElement natureOfCall = _mainWindow.FindFirst(TreeScope.Descendants, idCondition5);
  InsertTextUsingUIAutomation(natureOfCall, "TRAF WARN");

  PropertyCondition idCondition11 = new PropertyCondition(AutomationElement.AutomationIdProperty, "4935");
  AutomationElement location = _mainWindow.FindFirst(TreeScope.Descendants, idCondition11);
  InsertTextUsingUIAutomation(location, incident.Location);

  PropertyCondition idCondition12 = new PropertyCondition(AutomationElement.AutomationIdProperty, "2876");
  AutomationElement city = _mainWindow.FindFirst(TreeScope.Descendants, idCondition12);
  InsertTextUsingUIAutomation(city, incident.City);

  PropertyCondition idCondition15 = new PropertyCondition(AutomationElement.AutomationIdProperty, "5693");
  AutomationElement officer = _mainWindow.FindFirst(TreeScope.Descendants, idCondition15);
  InsertTextUsingUIAutomation(officer, incident.Officer);

  PropertyCondition idCondition19 = new PropertyCondition(AutomationElement.AutomationIdProperty, "4023");
  AutomationElement fromDate = _mainWindow.FindFirst(TreeScope.Descendants, idCondition19);
  InsertTextUsingUIAutomation(fromDate, incident.FromDate);

  PropertyCondition idCondition20 = new PropertyCondition(AutomationElement.AutomationIdProperty, "4042");
  AutomationElement fromTime = _mainWindow.FindFirst(TreeScope.Descendants, idCondition20);
  InsertTextUsingUIAutomation(fromTime, incident.FromTime);

  PropertyCondition idCondition21 = new PropertyCondition(AutomationElement.AutomationIdProperty, "7556");
  AutomationElement toDate = _mainWindow.FindFirst(TreeScope.Descendants, idCondition21);
  InsertTextUsingUIAutomation(toDate, incident.ToDate);

  PropertyCondition idCondition22 = new PropertyCondition(AutomationElement.AutomationIdProperty, "7576");
  AutomationElement toTime = _mainWindow.FindFirst(TreeScope.Descendants, idCondition22);
  InsertTextUsingUIAutomation(toTime, incident.ToTime);

  PropertyCondition idCondition30 = new PropertyCondition(AutomationElement.AutomationIdProperty, "2001");
  AutomationElement remarks = _mainWindow.FindFirst(TreeScope.Descendants, idCondition30);
  InsertTextUsingUIAutomation(remarks, incident.Remarks);


  MessageBox.Show("Incident was transferred.");
}

这是StructureChangedEvent的事件处理函数:

Here's the event handler for the StructureChangedEvent:

 private void OnStructureChanged(object sender, StructureChangedEventArgs e)
{
  AutomationElement element = sender as AutomationElement;

  if (e.StructureChangeType == StructureChangeType.ChildAdded)
  {
    Object windowPattern;
    if (false == element.TryGetCurrentPattern(WindowPattern.Pattern, out windowPattern))
      return;

    if (element.Current.Name == "Help")
    {
      // How do we want to handle this???
      MessageBox.Show("Waiting 30 seconds to allow user to resolve data issue.");
      Thread.Sleep(30000);
    }
  }
}

这篇关于如果我以编程方式激活另一个应用程序中的窗口,我可以检测到它失去焦点吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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