Appium can't locate collapsed element - wpf

I'm trying to access the Type property of the custom prompt dialog from an automation test. So the element for the Type (text box or text block) is collapsed because no one needs to see it, I just need it for logical processing on automation side.
I don't understand why it can't be located despite being available in the tree. or is there another why to get such access?
XAML:
<controls:PromptDialog ...
AutomationProperties.AutomationId="PromptView"
d:DataContext="{d:DesignInstance Type=viewModels:PromptViewModel}">
<Grid Margin="{StaticResource MarginThickness}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="{StaticResource Gutter}" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--Prompt-->
<Grid Grid.Row="0"
Visibility="{Binding IsShowingPrompt, Converter={StaticResource BooleanToVisibilityConverter}}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="4" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{StaticResource Gutter}" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--Image-->
<ContentControl Grid.Row="0"
Grid.Column="0"
Content="{Binding}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewModels:PromptViewModel}">
<Image Name="Image" />
//displaying image per type
</ContentControl.Resources>
</ContentControl>
<ScrollViewer Grid.Row="0"
Grid.Column="2"
Focusable="False"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
MaxHeight="400">
<StackPanel>
<TextBlock behaviors:TextBoxHyperlinkBehavior.Text="{Binding Text}"
TextWrapping="Wrap"
Focusable="False"
VerticalAlignment="Center"
HorizontalAlignment="Left"
FontFamily="{Binding Font.Name}"
Foreground="{Binding FontColor}"
AutomationProperties.AutomationId="PrompView_Text" />
<TextBox Visibility="Collapsed"
Text="{Binding Type}"
AutomationProperties.AutomationId="PromptView_Type" />
</StackPanel>
</ScrollViewer>
<!--Commands-->
<UniformGrid Grid.Row="2" Rows="1" HorizontalAlignment="Right">
// buttons
</UniformGrid>
</Grid>
</controls:PromptDialog>
Appium:
public IVisualElement Type => _appiumSession.CreateVisualAppiumElement("PromptView_Type");
Or
public AppiumWebElement Type => _appiumSession.FindElementByAccessibilityId("PromptView_Type");
WPF Snoop:
Error:
OpenQA.Selenium.WebDriverTimeoutException : Timed out after 10 seconds
---- OpenQA.Selenium.WebDriverException : An element could not be located on the page using the given search parameters.
Any pointers are highly appreciated,
thanks

There were several times when I used Snoop and it found more elements/attributes that Appium can access.
That is why now I am using Accessibility Insights for Windows. Of course you can use inspect.exe, but Accessibility Insights for Windows is the recommended from Microsoft. You can also try WinAppDriver UI Recorder that is generating XPaths.
If your element is not present in Accessibility Insights for Windows Appium will not be able to locate it.

According to documentation:
https://learn.microsoft.com/en-us/dotnet/api/system.windows.visibility?view=net-5.0
Collapsed elements are not rendered and NOT in layout.
Why not to use Visibility.Hidden instead, or Visibility.Visible with height of 0px.

I don't know anything about Appium, but the problem could be solve with .net automation api very easily.
// Must find top window of app first or could cause overflow easily.
var topWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children,
new PropertyCondition(AutomationElement.AutomationIdProperty, "Id of top window"));
// Find out your target element if it's in visual tree, whatever it's collapsed or not.
// You can also Find out another element in the middle first to reduce the search work.
var target = topWindow.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, "PromptView_Type"));
// retrieve the value.
var val = ((ValuePattern)target.GetCurrentPattern(ValuePattern.Pattern)).Current.Value;
You have to add reference to UIAutomationClient.dll and UIAutomationType.dll to make this code work.
Update for .net core app
For .net core(3.0, 3.1, 5.0), there's a huge difference about how an automation peer answer inquiry than .net framework app. Automation peer will not answer inquiry if it's offscreen(control's visibility had been set to collapsed or hidden) unless inquiry was targeting raw view. So we have to force inquiry target to make it works.
var topWindow = AutomationElement.RootElement.FindFirst(TreeScope.Children, new PropertyCondition(AutomationElement.AutomationIdProperty, "Id of top window"));
AutomationElement target = null;
var cr = new CacheRequest()
{
TreeFilter = Automation.RawViewCondition,
};
using (cr.Activate())
{
target = topWindow.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.AutomationIdProperty, "PromptView_Type"));
}

Related

How to add controls dynamically to a UserControl through user's XAML, 4.0

I want to create a user control that contains a Image and a Conainer that will allow the user to add his/her own controls to the user control dynamically in XAML. I am using VS 2010, .NET 4.0
I have created following code.
UserController.xaml
<Grid DockPanel.Dock="bottom">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Height="Auto" Grid.Row="0" Grid.Column="0">
<Image />
</StackPanel>
<Grid>
<ContentControl Content="{Binding Innercontent}" />
</Grid>
</Grid>
ModeViewCode, Innercontent is an DependencyProperty property
public static DependencyProperty InnerContentProperty = DependencyProperty.Register("InnerContent", typeof(UIElement), typeof(Footer))
public UIElement InnerContent
{
get { return (UIElement)GetValue(InnerContentProperty); }
set { SetValue(InnerContentProperty, value); }
}
Created a DataTemplate which consumes the usercontrol.
<users:Footer HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<users:Footer.InnerContent>
<StackPanel Orientation="Horizontal" x:Name="tst">
<commoncontrols:Button />
</StackPanel>
</users:Footer.InnerContent>
</users:Footer>
when code is complied it gives me following error message.
Error 275 Unknown build error, 'Index (zero based) must be greater than or equal to zero and less than the size of the argument list. Line 2582 Position 23.' at this line (users:Footer.InnerContent).
Got help from following psot Help
Any help will be appreciated.

How to dynamically add buttons and Silverlight player in a Grid?

I'm basically trying to create the following set of code dynamically/programmatically but I'm unsure of how to do it.
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<smf:SMFPlayer x:Name="player" Grid.Row="0" AutoPlay="False">
<smf:SMFPlayer.Playlist>
<media:PlaylistItem
DeliveryMethod="AdaptiveStreaming"
MediaSource="http://video3.smoothhd.com.edgesuite.net/ondemand/Big%20Buck%20Bunny%20Adaptive.ism/Manifest"/>
<media:PlaylistItem
DeliveryMethod="AdaptiveStreaming"
SelectedCaptionStreamName="textstream_eng"
MediaSource="http://streams.smooth.vertigo.com/elephantsdream/Elephants_Dream_1024-h264-st-aac.ism/manifest"/>
</smf:SMFPlayer.Playlist>
</smf:SMFPlayer>
<StackPanel Grid.Row="1" Orientation="Horizontal" Background="Transparent">
<Button x:Name="test1" Height="30" Width="70" Content="Test 1"/>
<Button x:Name="test2" Height="30" Width="70" Content="Test 2"/>
</StackPanel>
</Grid>
Here's how it looks statically:
First of all, you must give a name to your StackPanel like this;
<StackPanel x:Name="spBottom" Grid.Row="1" Orientation="Horizontal" Background="Transparent">
<Button x:Name="test1" Height="30" Width="70" Content="Test 1"/>
<Button x:Name="test2" Height="30" Width="70" Content="Test 2"/>
</StackPanel>
And then, you must add the following lines in code-behind;
For iLoop As Integer = 0 to 4
Dim btn As New Button With {.Content = "Button" & iLoop}
spBottom.Children.Add(btn)
Next iLoop
I hope this will be help to you!
The controls without an xmlns (XML namespace) prefix can be created in your code-behind without adding any usings. For example, in C# you can recreate the StackPanel from your XAML using the following code:
StackPanel panel = new StackPanel() { Orientation = Orientation.Horizontal, Background = null };
panel.SetValue(Grid.RowProperty, 2);
LayoutRoot.Children.Add(panel);
The elements with an xmlns prefix, anything with a colon, such as <smf: require knowledge of the namespace in the codebehind. The associated namespaces are defined in the first element and look like xmlns:smf="PathToTheNamespace". This namespace is often refrenced in a codebehind file in C# by adding a using PathToTheNamespace statement at the top.

WP7/Silverlight: how to disable/remove adctrol from visual tree

I am building a app that supports trial and I want to show ads in trials and no ads in paid. Upon investigation I found that the only way to disable the ads for paid version is to remove the adcontrol completely from the visual tree.
Now my question is how do I remove the adcontrol from my visual tree in my code when I detect it is a paid version and not a trial. Can you please help?
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
...
</Grid>
<Grid Grid.Row="1">
...
</Grid>
<Grid Grid.Row="2">
<ad:AdControlx:Name="itemAds" .../>
</Grid>
</Grid>
If you set the Visibility of the control to Visibility.Collapsed it will be removed from the visual tree.
You therefore just need one line of code:
itemAds.Visibility = Visibility.Collapsed;
You don't even need to name the grid:
var parent = itemAds.Parent as Grid;
if (parent != null)
{
parent.Children.Remove(itemAds);
}
Could you name the Grid that is wrapping the AdControl and then call, myGrid.Children.Clear() ?

Wpf Resize object with window

Looked around to find a way to resize bind with the windows resize without explicitly telling my object to grab the windows size.
Here is the code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<WindowsFormsHost Background="{x:Null}" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" Name="windowsFormsHost1" VerticalAlignment="Top" Margin="-1,0,0,0">
<wf:Panel x:Name="pnlLivePreview" />
</WindowsFormsHost>
</Grid>
This was followed by the example showed here
Edit: Question: Why doesn't panel resize with the window ?
Simply remove the explicit Width and Height settings, and the HorizontalAlignment and VerticalAlignment settings, thus:
<WindowsFormsHost Background="{x:Null}"
Name="windowsFormsHost1"
Margin="-1,0,0,0">
<wf:Panel x:Name="pnlLivePreview" />
</WindowsFormsHost>
I'm going to throw a wild guess here, but since this is a WinForms panel, try setting it's Dock property to Fill thus:
<wf:Panel x:Name="pnlLivePreview" Dock="Fill" />
Really not sure it would work, if it doesn't work in markup, try doing it in code.
Bind your Height/Width to your window's height/width
<Window x:Name="Root_Window">
<Grid Height="{Binding ElementName=RootWindow, Path=ActualHeight}"
Width="{Binding ElementName=RootWindow, Path=ActualWidth}">
<!-- Content Here -->
</Grid>
</Window>
The answer: Problem is not the panel but the api used to create the content of it.

WPF Data Binding - Data Template is not Getting Values

I have the following DataTemplate:
<DataTemplate DataType="{x:Type Client:WorkItem}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Label Name="lblIDText" Margin="2">WI ID:</Label>
<Label Name="lblID" Margin="2" Grid.Column="1"
Target="{Binding Id}"></Label>
<Label Name="lblTitleText" Grid.Row="1" Margin="2">WI Title:</Label>
<Label Name="lblTitle" Margin="2" Grid.Row="2" Grid.ColumnSpan="2"
Target="{Binding Title}"></Label>
</Grid>
</DataTemplate>
in my <Window.Resources> section. It is meant to show the Id and Title of a WorkItem object (from namespace Microsoft.TeamFoundation.WorkItemTracking.Client.)
I try to put this in a TabItem in a TabControl and it only shows the static text. (The WorkItem ID and title do not show, but the static text in my template does.)
Clearly the template is being fired, but the binding is not working and I can't seem to see why.
Here is my C# that calls it:
private void PickWorkItem_Click(object sender, RoutedEventArgs e)
{
int Id = int.Parse(((Button) e.OriginalSource).Tag.ToString());
_mediator.PickedWorkItem = GetWorkItemInQueryResultListByID(Id);
tabAddLinks.DataContext = _mediator.PickedWorkItem;
tabAddLinks.Content = _mediator.PickedWorkItem;
}
I tried it with DataContext in and out and it works the same. When I debug, the value for _mediator.PickedWorkItem is set correctly (Id and Title are both fine).
Any ideas on how to fix this would be appreciated.
You're binding the Label's Target property, when you actually want to be binding it's Content property:
<Label Content="{Binding Id}"/>
Also, consider using a TextBlock instead of a Label if you don't need the extra functionality a Label provides:
<TextBlock Text="{Binding Id}"/>
You are binding Label.Target. Target is the UIElement being labelled. You need to bind Label.Content, or change it to a TextBlock and bind TextBlock.Text.
(My guess would be that you were trying to bind a non-existent Label.Text property and Intellisense helpfully chose Target for you instead...!)
I'm pretty new to WPF, so excuse me if I'm off base, but don't you need to set the Content property of the label, not the Target?

Resources