我正在尝试为应用创建功能,但首先要在测试应用中对其进行尝试。基本上,我有一个带有三个按钮的应用程序,当用户按一个绿色按钮时,我希望该按钮将字符串发送到另一个正在显示图像的应用程序。该应用程序将读取字符串并显示绿色图像。将字符串数据从一个应用程序发送到另一个应用程序的最佳方法是什么?
我已经研究了多种与应用程序交流的方法,但是我没有找到很好的解释
答案 0 :(得分:0)
我提出了一种不同的方法来让应用程序进行通信(在这种情况下,这是一种持续的交互:只有一个应用程序与其他应用程序对话)。
使用UI自动化,您可以半透明的方式在另一个应用程序中获取或设置Controls属性的值。还接收或引起事件,检测应用程序何时运行或关闭其他有趣的 activity 。此处的常规文档:
Windows Accessibility API reference - UI Automation
.Net Framework UI Automation Fundamentals
您有两个具有简单要求的简单应用程序,因此该任务非常简单:
由于您需要发送一些字符串来更改PictureBox的颜色,因此我们可以使用TextBox控件,该控件将接收字符串并在颜色中转换 command 或触发另一个预定义的行为。
使用UI自动化,这两个应用程序可以独立运行,然后以不同的方式确认其他对象的存在。例如,使用WindowPattern.WindowOpenedEvent,我们可以检测应用程序何时运行,并以不同的方式确定它是否有趣。有关实现,请参见以下问题:
Run event when any Form loads
这是另一个问题,identify an application based on the content of a child control。
在这里(为了简短起见),我只是枚举正在运行的具有接口的应用程序,并使用ComboBox作为选择器来选择一个。
private void comboBox1_SelectionChangeCommitted(object sender, EventArgs e)
{
var window = AutomationElement.FromHandle((IntPtr)comboBox1.SelectedValue);
if (window != null) {
GetCommElement(window, ControlType.Edit);
}
}
private void GetCommElement(AutomationElement parent, ControlType controlType)
{
element = parent.FindFirst(TreeScope.Subtree,
new PropertyCondition(AutomationElement.ControlTypeProperty, controlType));
}
如果找到了所选应用程序的TextBox,我们将得到其ValuePattern(一种UI自动化模式,允许设置控件的值),并将其Text属性设置为与名称对应的字符串颜色:
(请注意,仅非多行Edit控件(WinForms文本框)支持 ValuePattern
。多行Edit控件不支持,仅TextRangePattern)
private void btnColor_Click(object sender, EventArgs e)
{
if (element == null) return;
var ctrl = sender as Control;
if (element.TryGetCurrentPattern(ValuePattern.Pattern, out object pattern)) {
(pattern as ValuePattern).SetValue(ctrl.Text);
this.Activate();
}
}
接收命令的应用程序,使用其TextBox控件的 TextChanged
事件从另一个应用程序接收字符串并确定要执行的操作:
(请注意,文本框可以在屏幕外,但是它的 Visible
属性必须设置为true
)
private void textBox1_TextChanged(object sender, EventArgs e)
{
var color = Color.FromName((sender as Control).Text);
pictureBox1.BackColor = (color.IsKnownColor) ? color: Color.White;
}
示例功能:
两个应用程序的完整源代码:
UI Automation需要引用以下程序集: UIAutomationClient
和 UIAutomationTypes
UIAClientApp
:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Automation;
public partial class UIAClientApp : Form
{
AutomationElement element = null;
private void comboBox1_DropDown(object sender, EventArgs e)
{
var dict = new Dictionary<IntPtr, string>();
foreach(var proc in Process.GetProcesses().Where(p => p.Id > 4 &&
p.MainWindowHandle != this.Handle &&
!string.IsNullOrEmpty(p.MainWindowTitle)).ToList())
{
dict.Add(proc.MainWindowHandle, proc.MainWindowTitle);
}
comboBox1.DisplayMember = "Value";
comboBox1.ValueMember = "Key";
comboBox1.DataSource = dict.ToList();
}
private void comboBox1_SelectionChangeCommitted(object sender, EventArgs e)
{
lblCurrentApp.Text = comboBox1.SelectedItem.ToString();
var window = AutomationElement.FromHandle((IntPtr)comboBox1.SelectedValue);
if (window != null) {
GetCommElement(window, ControlType.Edit);
}
}
private void GetCommElement(AutomationElement parent, ControlType controlType)
{
element = parent.FindFirst(TreeScope.Subtree,
new PropertyCondition(AutomationElement.ControlTypeProperty, controlType));
}
private void btnColor_Click(object sender, EventArgs e)
{
if (element is null) return;
var ctrl = sender as Control;
if (element.TryGetCurrentPattern(ValuePattern.Pattern, out object pattern)) {
(pattern as ValuePattern).SetValue(ctrl.Text);
this.Activate();
}
}
}
UIATestApp
:
using System.Drawing;
using System.Windows.Forms;
public partial class UIATestApp : Form
{
public UIATestApp() => InitializeComponent();
private void textBox1_TextChanged(object sender, EventArgs e)
{
var color = Color.FromName((sender as Control).Text);
pictureBox1.BackColor = (color.IsKnownColor) ? color: Color.White;
}
}