मैं Microsoft UI Automation का उपयोग कर रहा हूं (यानी AutomationElement
) मेरे आवेदन के खिलाफ स्वचालित स्वीकृति परीक्षण चलाने के लिए। यह अच्छी तरह से चला गया है, लेकिन मैंने ऐसी स्थिति का सामना किया है जो स्वचालन ढांचे के संपर्क में नहीं आता है।
मेरे पास एक है ItemsControl
(हालांकि मैं इसके व्युत्पन्न नियंत्रणों में से एक का उपयोग कर रहा था, जैसे ListBox
) और मैं CollectionViewSource
आइटम्स को ग्रुप करने के लिए। यहाँ प्रदर्शित करने के लिए एक पूर्ण विंडो है:
<Window x:Class="GroupAutomation.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Orchestra">
<Window.Resources>
<!-- Take some simple data -->
<XmlDataProvider x:Key="SampleData" XPath="Orchestra/Instrument">
<x:XData>
<Orchestra xmlns="">
<Instrument Name="Flute" Category="Woodwind" />
<Instrument Name="Trombone" Category="Brass" />
<Instrument Name="French horn" Category="Brass" />
</Orchestra>
</x:XData>
</XmlDataProvider>
<!-- Add grouping -->
<CollectionViewSource Source="{Binding Source={StaticResource SampleData}}" x:Key="GroupedView">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="@Category" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<!-- Show it in an ItemsControl -->
<ItemsControl ItemsSource="{Binding Source={StaticResource GroupedView}}" HorizontalAlignment="Left" Margin="4">
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Padding="4" Margin="4" Background="#FFDEDEDE">
<StackPanel>
<Label Content="{Binding XPath=@Name}" />
<Button Content="Play" />
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
यह एक विंडो उत्पन्न करता है जिसमें उनकी श्रेणियों में समूहित आइटम होते हैं, और प्रत्येक आइटम में एक बटन होता है जिसे मैं UI ऑटोमेशन के साथ क्लिक करना चाहता हूं:
<उप>(स्रोत: brizzly.com)
हालांकि, अगर मैं UISpy.exeमें देखता हूं। a> (या AutomationElement
के साथ नेविगेट करें) मुझे केवल समूह दिखाई देते हैं (यहां तक कि रॉ व्यू में भी):
<उप>(स्रोत: brizzly.com)
जैसा कि आप देख सकते हैं, समूह तो हैं लेकिन उनमें कोई आइटम नहीं है, इसलिए बटन खोजने के लिए कहीं नहीं है। मैंने इसे डब्ल्यूपीएफ 3.5 एसपी1 और डब्ल्यूपीएफ 4.0 दोनों में आजमाया है और एक ही परिणाम प्राप्त किया है।
क्या समूहीकृत वस्तुओं पर UI स्वचालन का उपयोग करना संभव है, और यदि हां, तो कैसे?
4 जवाब
मुझे इस समस्या का सामना करना पड़ा और मैंने http://www.colinsalmcorner.com/post/genericautomationpeer--helping-the-coded-ui-framework-find-your-custom-controls और एक जोड़ना GroupItem
s के लिए विशेष मामला।
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Media;
using System.Xml;
namespace ClassLibrary1
{
public class MyItemsControl : ItemsControl
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new GenericAutomationPeer(this);
}
}
public class GenericAutomationPeer : UIElementAutomationPeer
{
public GenericAutomationPeer(UIElement owner) : base(owner)
{
}
protected override List<AutomationPeer> GetChildrenCore()
{
var list = base.GetChildrenCore();
list.AddRange(GetChildPeers(Owner));
return list;
}
private List<AutomationPeer> GetChildPeers(UIElement element)
{
var list = new List<AutomationPeer>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = VisualTreeHelper.GetChild(element, i) as UIElement;
if (child != null)
{
AutomationPeer childPeer;
if (child is GroupItem)
{
childPeer = new GenericAutomationPeer(child);
}
else
{
childPeer = UIElementAutomationPeer.CreatePeerForElement(child);
}
if (childPeer != null)
{
list.Add(childPeer);
}
else
{
list.AddRange(GetChildPeers(child));
}
}
}
return list;
}
}
}
मुझे आशा है कि इससे किसी को अभी भी उत्तर खोजने में मदद मिलेगी!
मैं बटनों के बारे में 100% निश्चित नहीं हूं, लेकिन TextBlock
नियंत्रण जो DataTemplate
के अंदर हैं, उन्हें UI ऑटोमेशन ट्री में नहीं रखा जाता है। जाहिरा तौर पर यह 1000 के असफल टेक्स्टब्लॉक से बचने के लिए एक अनुकूलन है।
आप सबक्लासिंग टेक्स्टब्लॉक द्वारा इसके आसपास काम कर सकते हैं। ये मेरा:
public class AutomatableTextBlock : TextBlock
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new AutomatableTextBlockAutomationPeer(this);
}
class AutomatableTextBlockAutomationPeer : TextBlockAutomationPeer
{
public AutomatableTextBlockAutomationPeer(TextBlock owner)
: base(owner)
{ }
protected override bool IsControlElementCore()
{ return true; }
}
}
नोट: यूआई ऑटोमेशन Canvas
, Panel
जैसे कई अन्य नियंत्रणों को भी उजागर नहीं करता है, आप उन्हें एक समान उपवर्ग के साथ दिखाने के लिए प्राप्त कर सकते हैं।
ऐसा कहकर, मुझे नहीं पता कि Button
क्यों दिखाई नहीं दे रहा है.... Hrmmm
मैंने टेम्पलेट खोजने के लिए AutomationElement.FindFirst
का उपयोग करने के बाद पेड़ को मैन्युअल रूप से नेविगेट करने के लिए TreeWalker.RawViewWalker
का उपयोग करके अपने आवेदन में इसे हल करना समाप्त कर दिया। ऐसा लगता है कि FindFirst
किसी अन्य व्यक्ति के एप्लिकेशन को स्वचालित करते समय आपकी इच्छित सभी जानकारी को विश्वसनीय रूप से बहिष्कृत कर देता है। RawViewWalker
काम करने लगता है जब तत्व "ऑब्जेक्ट्स का निरीक्षण" में दिखाई देते हैं, लेकिन UISpy या आपके एप्लिकेशन में नहीं।
स्वचालित स्क्रिप्ट लिखने के लिए आप किस टूल का उपयोग कर रहे हैं? मैंने सोचा होगा कि Win32 पेड़ (जैसा कि यूआईएसपी द्वारा सामने आया) पर भरोसा करने के बजाय डब्ल्यूपीएफ के लॉजिकल/विजुअल पेड़ में ड्रिल करने का विकल्प होगा।
यदि आप Snoop का उपयोग करके उसी एप्लिकेशन को देखते हैं, तो आपको पूर्ण दृश्य और तार्किक पेड़ दिखाई देंगे।