I have been trying to expose RecordListcontrol for Coded UI Automation for days, have not found a creditable have not found a creditable solution yet, and then I found the following site http://help.infragistics.com/Help/Doc/WPF/2015.1/CLR4.0/html/InfragisticsWPF4.DataPresenter.v15.1~Infragistics.Windows.Automation.Peers.DataPresenter.RecordListControlAutomationPeer.html
claiming that RecordListControlAutomationPeer exposes RecordListControl for UI automation; however, it does not give example(s) regarding how to the RecordListControlAutomationPeer to expose the RecordListControl for Coded UI automation.
Can anyone please be so kind to so show me or give me example on how I can use RecordListControlAutomationPeer to expose RecordListControl for Coded UI automation?
I have RecordListControl type specified in WPF/XAMAL file as follows:
<Style TargetType="{x:Type igDP:RecordListControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type igDP:RecordListControl}">
<ScrollViewer CanContentScroll="True" Focusable="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ItemsPresenter>
<AutomationProperties.AutomationId>"AutomationIdTestingName"</AutomationProperties.AutomationId>
</ItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hi Trung,
Is there a particular reason you need to get the RecordListControl through automation peers? Usually you don't need to mess around with the automation peers directly when using Coded UI Test as the XamDataGrid should support it. Is there some issue you are running into?
Thank you very much for your question/replay, Rob.
I am dealing with developed/existing application. I am able to subclass the XAMDataGrid and assign AutomationId to it; however, Coded UI Code Builder cannot see the RecordListControl inside the XamDataGrid (TmXamDataGrid) during recording. My XamDataGrid contains a RecordListControl which contains a list of records with multiple columns of fields which I need to be able identify, excess, and validate its properties' values during Coded UI automation; thus, I believe I need to use RecordListControlAutomationPeer to expose RecordListControlAutomation for Coded UI Automation; unless, I am looking at this the wrong angle or unless you can show me a way that I can expose the information of RecordListControl to the Coded UI Code Builder without using RecordListControlAutomationPeer.
Note: I cannot subclass RecordListControl to create automation peer for it because it is sealed.
Here is the XAMAL for the XamData and the RecordListControl:
<local:TmXamDataGrid AutomationProperties.AutomationId="AutomationIdForInventroyViewHomeDataGrid" RecordActivated="GridControl_RecordActivated" x:Name="GridControl" x:FieldModifier="public"
Width="Auto" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="1"
GroupByAreaLocation="None">
<local:TmXamDataGrid.Resources>
<Style TargetType="{x:Type igDP:SummaryResultPresenter}">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="FontWeight" Value="Bold"/>
<Style TargetType="{x:Type local:AutomatableInventoryHomeViewDataRecordPresenter}">
<Setter Property="HorizontalContentAlignment" Value="Right" />
<!-- override global style-->
<AutomationProperties.AutomationId>"AutomationIdTestingTrungmai"</AutomationProperties.AutomationId>
<Style TargetType="{x:Type local:AutomatableInventoryHomeViewCellValuePresenter}">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self},
Path=Record.DataItem.Detail.PendingState, Converter={StaticResource pendingBackgroundBrushConverter}}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataItem.IsVisible}" Value="False">
<Setter Property="Height" Value="0"/>
</DataTrigger>
</Style.Triggers>
</local:TmXamDataGrid.Resources>
<local:TmXamDataGrid.FieldLayoutSettings>
<igDP:FieldLayoutSettings AutoGenerateFields="False" HighlightAlternateRecords="True"/>
</local:TmXamDataGrid.FieldLayoutSettings>
</local:TmXamDataGrid>
Visual Representation of XamDataGrid of RecordListControl
Usually when you subclass an existing control you're doing this to change the control behavior in a subtle way and this shouldn't impact UI automation unless big changes are made to the internal structure of the datagrid. If big changes were made then I would expect that things would no longer be found. I'll assume that big structural changes haven't been made.
Do you know if the grid has set either of these two properties?
http://help.infragistics.com/doc/WPF/2015.1/CLR4.0/?page=InfragisticsWPF4.DataPresenter.v15.1~Infragistics.Windows.Automation.Peers.DataPresenter.DataPresenterBaseAutomationPeer~ProcessRecordsInViewOnly.html
http://help.infragistics.com/doc/WPF/2015.1/CLR4.0/?page=InfragisticsWPF4.DataPresenter.v15.1~Infragistics.Windows.Automation.Peers.DataPresenter.DataPresenterBaseAutomationPeer~ProcessVisualTreeOnly.html
If these properties were set then it can impact UI automation on the grid. Generally you set these properties if you want to disable the automation so if you are setting these anywhere in the grid I recommend that you remove them.
These are the only two things that come to mind when thinking of ways for UI automation to fail to recognize elements, even with subclassing.
Hi, Rob.
Thank you very much for your info and help. I did subclass the XAMDataGrid, but did not make any major structural changes.
None of the two properties were set. I have went back and performed subclass on XAMDataDataGrid and generate generic automation peers for all of its children.
Doing so allows the Coded UI Code Builder to see
SummaryResultPresenter
CellValuePresenter
DataRecordPresenter
The U, D, N, C tabs above are TabControl. I can access the control and assign the AutomationId fine.
1) However, each time I click on the each of the 0's in the In,
I can only see:
AutomationIdForInventoryHomeViewSummaryResultPresenterInfragistics.Windows.DataPresenter.SummaryResultEntry
I want to be able to see:
Note: 'In' is the label for the SummaryResults Label.
Note: the numbers: 100, 50, 25, 5, 2, 1 are the columns' name or header of the grid.
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In Total
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In 100
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In 50
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In 25
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In 2
AutomationutomationIdForInventoryHomeViewSummary ResultPresenter In 1
Can you please show me how I can achieve this?
2) Each time, I click each of the cells in the grid and examine it with Coded UI Code Test Builder's UI Spy, I can only see
For example, any cell in 1st Data Record, I can only see: AutomationIdForInventoryHomeViewCellValuePresenterDataRecord- 0 type: O.
For example, any cell in 2nd Data Record, I can only see: AutomationIdForInventoryHomeViewDataRecordPresenterDataRecord- 1 type: U
For example, any cell in 3rd Data Record, I can only see: AutomationIdForInventoryHomeViewDataRecordPresenterDataRecord- 2 type: C
I want to be able do the following:
If I want to be able to assign an AutomationId for 1st Data Record's 1st cell, and when I examine it with Coded UI Code Builder UI Spy, I want to be able
to see: AutomationIdForInventoryHomeViewCellValuePresenter DataRecord 0 I Value
If I want to be able to assign an AutomationId for 2nd Data Record's 2nd cell, and when I examine it with Coded UI Code Builder UI Spy, I want to be able
to see: AutomationIdForInventoryHomeViewCellValuePresenter DataRecord 1 Total Value
If I want to be able to assign an AutomationId for 3nd Data Record's 3rd cell, and when I examine it with Coded UI Code Builder UI Spy, I want to be able
to see: AutomationIdForInventoryHomeViewCellValuePresenter DataRecord 2 50 Value
If I want to be able to assign an AutomationId for 4th Data Record's 4th cell, and when I examine it with Coded UI Code Builder UI Spy, I want to be able
to see: AutomationIdForInventoryHomeViewCellValuePresenter DataRecord 3 25 Value
Basically I want to be able to append the Record Index and Grid Column Header to the AutomationId for each cell that locates at DataRecord#,ColumnHeader#
as follow: "AutomationIdForInventoryHomeViewCellValuePresenter DataRecord#,ColumnHeader#"
3) Each time, I click each of the records in the grid and examine it with Coded UI Code Test Builder's UI Spy, I can only see
For example, any cell in 1st Data Record, I can only see: AutomationIdForInventoryHomeViewDataRecordPresenterDataRecord- 0 type: O.
I want o be able to see only as following:
AutomationIdForInventoryHomeViewDataRecordPresenter DataRecord- 0
AutomationIdForInventoryHomeViewDataRecordPresenterDataRecord- 1
AutomationIdForInventoryHomeViewDataRecordPresenterDataRecord- 2
I am using the following XAML file:
<Grid >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<igWindows:XamTabControl Width="Auto" Height="Auto" Grid.RowSpan="2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
ItemsSource="{Binding InventoryChipsets}"
Focusable="False" AutomationProperties.AutomationId ="AutomationIdForInventoryHomeViewTabControl" x:Name="TabControl" x:FieldModifier="public"
SelectionChanged="TabControl_SelectionChanged" RequestBringIntoView="TabControl_RequestBringIntoView">
<!-- need to create task for creating scrolling tab control, this is quick and dirty-->
<igWindows:XamTabControl.Template>
<ControlTemplate TargetType="{x:Type igWindows:XamTabControl}">
<DockPanel>
<controls:SwipeScroller Focusable="False" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<ScrollViewer DockPanel.Dock="Top" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<StackPanel Orientation="Horizontal" IsItemsHost="True" />
</controls:SwipeScroller>
<Border>
<ContentPresenter ContentSource="SelectedContent"/>
</Border>
</DockPanel>
</igWindows:XamTabControl.Template>
<igWindows:XamTabControl.ItemContainerStyle>
<Style TargetType="{x:Type igWindows:TabItemEx}" BasedOn="{StaticResource TabItemExStyle_TopColorCoded}">
<Setter Property="Header" Value="{Binding FormattedChipsetName}"/>
<Setter Property="AutomationProperties.AutomationId" Value="{Binding FormattedChipsetName, StringFormat='{}AutomationIdForInventoryHomeViewChipsetTabName{0}'}"/>
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</igWindows:XamTabControl.ItemContainerStyle>
</igWindows:XamTabControl>
<Button Style="{StaticResource ButtonCtrlTemplate_B1_ColorCoded}"
Margin="0,0,5,0" Height="35" Width="100" Grid.RowSpan="2" Grid.ColumnSpan="3" HorizontalAlignment="Right"
Name="BtnRack"
DataContext="{Binding SelectedRack}"
Content="{Binding Name}"
Command="{Binding DataContext.SelectRackCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"
Visibility="{Binding DataContext.ButtonSelectRackVisible, Converter={StaticResource BoolToVisibilityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}"/>
<TextBlock Foreground="White" Grid.Column="1" Grid.Row="0" Focusable="False" TextAlignment="Center" Margin="2,-36,2,40" Text="{x:Static properties:Resources.CurrentInventoryTotalString}"/>
<Border Margin="0,-38,0,42" BorderBrush="White" Grid.Column="1" Grid.Row="1" Style="{StaticResource DetailBorderStyle}" Visibility="{Binding Path=IsVisible, Converter={StaticResource BoolToVisibilityConverter}}">
<TextBlock Style="{StaticResource DetailTextBlockStyle}" Foreground="White" Text="{Binding FormattedAllChipsetTotal}"/>
<Border BorderBrush="DarkGray" BorderThickness="2" Grid.ColumnSpan="3" Background="{StaticResource ContrastColorBrush}" Grid.Row="2" Width="Auto" Height="Auto">
</Grid>
<local:AutomatableInventoryHomeViewXamDataGrid RecordActivated="GridControl_RecordActivated" AutomationProperties.AutomationId ="AutomationIdForXamDataGrid" x:Name="GridControl" x:FieldModifier="public"
<local:AutomatableInventoryHomeViewXamDataGrid.Resources>
<Setter Property="AutomationProperties.AutomationId" Value="{Binding StringFormat='{}AutomationIdForInventoryHomeViewSummaryResultPresenter{0}'}"/>
<Style TargetType="{x:Type igDP:CellValuePresenter}">
<Setter Property="AutomationProperties.AutomationId" Value="{Binding StringFormat='{}AutomationIdForInventoryHomeViewCellValuePresenter{0}'}"/>
<Setter Property="AutomationProperties.AutomationId" Value="{Binding StringFormat='{}AutomationIdForInventoryHomeViewRecordListControl{0}'}"/>
<AutomationProperties.AutomationId>
AutomationIdForInventoryHomeViewItemsPresenter
</AutomationProperties.AutomationId>
<Style TargetType="{x:Type igDP:DataRecordPresenter}">
<!--Setter Property="AutomationProperties.AutomationId" Value="AutomationIdForInventoryHomeViewDataRecordPresenter"/-->
<Setter Property="AutomationProperties.AutomationId" Value="{Binding StringFormat='{}AutomationIdForInventoryHomeViewDataRecordPresenter{0}'}"/>
<Setter Property="AutomationProperties.AutomationId" Value ="AutomationIdForInventoryHomeViewDataItem"/>
</local:AutomatableInventoryHomeViewXamDataGrid.Resources>
<local:AutomatableInventoryHomeViewXamDataGrid.FieldLayoutSettings>
</local:AutomatableInventoryHomeViewXamDataGrid.FieldLayoutSettings>
</local:AutomatableInventoryHomeViewXamDataGrid>
Hello Trung,
I'm not sure what you mean by "generate generic automation peers". You shouldn't have to manually generate anything.
As for setting up the automation IDs for the SummaryResultPresenter, what you are seeing with the SummaryResultEntry is expected given the binding you have for the AutomationId:
"{Binding StringFormat='{}AutomationIdForInventoryHomeViewSummaryResultPresenter{0}'}"
The DataContext for the SummaryResultPresenter is just a SummaryResultEntry so all this binding is doing is calling ToString() on SummaryResultEntry which is why you get "AutomationIdForInventoryHomeViewSummaryResultPresenterInfragistics.Windows.DataPresenter.SummaryResultEntry". If you want more info like what column the summary belongs to you need to apply a Path to the binding so you can delve deeper into the SummaryResultEntry. Here is an example for how you can achieve the desired format:
<Setter Property="AutomationProperties.AutomationId" Value="{Binding Path=SummaryResult.SourceField.Name, StringFormat='{}AutomationIdForInventoryHomeViewSummaryResultPresenter In {0}'}"/>
This setter will produce the following result:
"AutomationIdForInventoryHomeViewSummaryResultPresenter In salary" (salary being my column name)
Your CellValuePresenter Id requirement is the same thing. The CellValuePresenter DataContext is a DataRecord so all your binding is doing is calling ToString() on the DataRecord and sticking that into the AutomationId. If you want a more column specific Id for the cell then you will need to change the binding. Maybe this will work for you:
<Setter Property="AutomationProperties.AutomationId"> <Setter.Value> <MultiBinding StringFormat="{}AutomationIdForInventoryHomeViewCellValuePresenter DataRecord {0} {1} Value"> <Binding Path="Index"/> <Binding RelativeSource="{RelativeSource Self}" Path="Field.Name"/> </MultiBinding> </Setter.Value></Setter>
Again, DataRecordPresenter Id requirements are the same thing. Just change the binding on the AutomationId to get the Id that you want:
<Setter Property="AutomationProperties.AutomationId" Value="{Binding Path=Index, StringFormat='{}AutomationIdForInventoryHomeViewDataRecordPresenter DataRecord {0}'}"