Winforms 如果我以编程方式激活另一个应用程序中的窗口,我能检测到它何时失去焦点吗?
请放心,我是一名尝试WinForms应用程序的web开发人员 回复时请不要评论我的申请目的是否是“最佳实践”,等等。。。这是我需要编写的应用程序,不管是好是坏,我不能浪费时间解释“为什么”。我请求你回复我的建议:(1)我想做的是可能的(2)什么是完成我想做的事情的“最佳”方式 所以,我想做的是: 我需要编写一个WinForms应用程序,从供应商应用程序读取数据,向最终用户显示某些记录,并允许他们选择将记录“传输”到另一个供应商应用程序。挂起…目标系统没有公开API,没有存储过程,没有提供插入数据的“好”方法,除了在GUI中键入数据。(相信我,一个由3人组成的团队调查了实现自动化的各种可能性) 因此,此WinForms应用程序将利用Microsoft.VisualBasic.Interaction.AppActivate(字符串)并将数据直接插入目标系统输入窗口中的字段。目标系统在某些字段上有F1帮助,因此,如果您将焦点放在该字段并按“F1”,或者,如果您在其中一个字段中输入无效数据,则会弹出一个名为“帮助”的子窗口以提供指导 因此,我的应用程序正在插入,使用SendKeys.SendWait(字符串)将数据写入此应用程序的字段,然后遇到一些无效数据,并弹出“帮助”窗口,我的应用程序继续写入其余数据,但现在所有数据都写入“帮助”窗口中的“1”字段,因为该窗口现在具有焦点 百万美元问题… 是否有办法从我的WinForms应用程序中检测到目标系统中的帮助窗口已被激活,以便我可以解决此问题?Winforms 如果我以编程方式激活另一个应用程序中的窗口,我能检测到它何时失去焦点吗?,winforms,c#-4.0,microsoft-ui-automation,Winforms,C# 4.0,Microsoft Ui Automation,请放心,我是一名尝试WinForms应用程序的web开发人员 回复时请不要评论我的申请目的是否是“最佳实践”,等等。。。这是我需要编写的应用程序,不管是好是坏,我不能浪费时间解释“为什么”。我请求你回复我的建议:(1)我想做的是可能的(2)什么是完成我想做的事情的“最佳”方式 所以,我想做的是: 我需要编写一个WinForms应用程序,从供应商应用程序读取数据,向最终用户显示某些记录,并允许他们选择将记录“传输”到另一个供应商应用程序。挂起…目标系统没有公开API,没有存储过程,没有提供插入数据
更新
第一次尝试这个应用程序时,我使用了UIAutomationClient库。我无法成功激活目标窗口并写入第一个字段。经过一天的斗争,我不得不开始寻找替代方案。我有了一些工作代码的开始。我想我已经足够了,这可能对其他人有用 我找到了一种使用UIAutomation库而不是Microsoft.VisualBasic库的方法。有很多尝试和错误,但这比我最初使用VisualBasic库的几次尝试要“流畅”得多 我使用StructureChanged事件检测在这个概念验证应用程序的上一次迭代中弹出的帮助窗口。我能够成功地检测到帮助窗口弹出,但是我在尝试处理帮助窗口的外观时遇到了障碍。我的应用程序中仍然有事件处理程序,但由于某些原因,帮助窗口现在没有弹出,我尝试将无效数据强制输入其中一个字段以测试帮助窗口的处理,而帮助窗口没有出现。这对我来说不是问题,因为帮助窗口给我带来了麻烦,但我觉得有必要提及它,因为这篇文章问我如何检测帮助窗口的外观 我使用的一些资源:
SetWinEventHook()。这确实有一个技巧可以变成哥特式的错误。至少考虑一个合适的UI自动化库,这样你就不必通过模拟击键来破解这个问题。汉斯,我试着先使用UIutoActudio客户端,但是由于目的地系统的更多问题,我无法完成我所需要的。这里有一个旧的VB6/VBA应用程序可以实现这一点,由于多种原因需要升级。。。我的合作伙伴和我决定尝试改进解决方案,避免使用VBA。经过尝试和失败后,我们重新开始使用Microsoft.VisualBasic.Interaction.AppActivate(),基本上是模仿遗留应用程序中的代码,但我们仍然致力于改进功能/性能。遗留应用程序实际上是另一回事。
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.");
}
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);
}
}
}