AutomationProperties.AutomationId 未公开自定义控件
AutomationProperties.AutomationId on custom control not exposed
我已经为这个问题苦苦思索了 3 天,一直没能找到答案。
我有一个用 WPF (dot Net 4.5) 编写的应用程序,我正在使用 Teststack.White 尝试编写一些自动化 GUI 测试用例。开发人员已将 x:Names 提供给某些控件,它们通过 Inspect/WPF Inspector/Visual UI Automation Verify 显示为 AutomationId 就好了。
还有其他一些隐藏得更深的控件,我的任务是为其提供自动化 ID(主要是作为练习,以便我可以更熟悉后端)。这是我一直在努力反对的地方。
我试过为控件提供 AutomationProperties.AutomationId(和 .Name)属性。我给了 AutomationProperties 一个名称 space 定义。我也确保 SWA.Peers 被引用。
我还没有尝试在 XAML 中使用 属性 设置器,因为它们目前没有多大意义,我希望不需要在 C# 中编写东西来设置它们(如果我这样做,我会这样做,但只是希望)。
我的一位同事坐下来,我们拿出了不暴露自动化 ID 的最低限度的设置 属性(不幸的是,他和其他开发人员都不知道为什么这没有发生)。看起来像:
MainWindow.xaml:
<Window x:Class="TestAutomationUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common"
Title="Test UI (Pick me)" Height="455.075" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/IconLabelButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel x:Name="PresentationRoot">
<common:IconLabelButton x:Name="TestButton" autoProp:AutomationProperties.AutomationId="TestButtonClick" Text="Stuff" Margin="245,0,214.4,0" RenderTransformOrigin="4.648,0.588" Height="32">
</common:IconLabelButton>
</StackPanel>
</Window>
IconLabelButton.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common">
<Style TargetType="common:IconLabelButton">
<Setter Property="Template" Value="{DynamicResource Asi.Ui.Common.IconLabelButton}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="FontWeight" Value="{DynamicResource Mobius.UI.Resources.Fonts.WeightLight}"/>
<Setter Property="Spacing" Value="10" />
</Style>
<ControlTemplate x:Key="Asi.Ui.Common.IconLabelButton" TargetType="common:IconLabelButton">
<Border Background="{TemplateBinding Background}" Height="30">
<Button Style="{DynamicResource Mobius.UI.Resources.Styles.IconButton}" Margin="0" Padding="0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Left"
Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}" Foreground="{TemplateBinding Foreground}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22" />
<ColumnDefinition Width="{TemplateBinding Spacing}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="22" Height="22">
<Path Margin="1" Height="20" Width="20" Fill="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" Data="{TemplateBinding Icon}" Stretch="Fill"/>
<Path Margin="1" Height="20" Width="20" Fill="{TemplateBinding AdornerIconFill}" Data="{TemplateBinding AdornerIcon}" Stretch="Fill"/>
</Grid>
<TextBlock Grid.Column="2" Text="{TemplateBinding Text}" VerticalAlignment="Center" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontWeight="{TemplateBinding FontWeight}"/>
</Grid>
</Button>
</Border>
</ControlTemplate>
</ResourceDictionary>
IconLabelButton.xaml.cs:
using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Asi.Ui.Common
{
public class IconLabelButton : Control
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(IconLabelButton), new PropertyMetadata(default(string)));
public static readonly DependencyProperty AdornerIconProperty =
DependencyProperty.Register("AdornerIcon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty IconButtonSizeProperty =
DependencyProperty.Register("IconButtonSize", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty AdornerIconFillProperty =
DependencyProperty.Register("AdornerIconFill", typeof(Brush), typeof(IconLabelButton), new PropertyMetadata(default(Brush)));
static IconLabelButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IconLabelButton), new FrameworkPropertyMetadata(typeof(IconLabelButton)));
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public object AdornerIcon
{
get { return GetValue(AdornerIconProperty); }
set { SetValue(AdornerIconProperty, value); }
}
public object Icon
{
get { return GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public GridLength Spacing
{
get { return (GridLength)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
public GridLength IconButtonSize
{
get { return (GridLength)GetValue(IconButtonSizeProperty); }
set { SetValue(IconButtonSizeProperty, value); }
}
public Brush AdornerIconFill
{
get { return (Brush)GetValue(AdornerIconFillProperty); }
set { SetValue(AdornerIconFillProperty, value); }
}
}
}
如果这是一个简单的问题(或者如果我问的不对),我深表歉意。我是一个入门级的程序员,对WPF/XAML.
只有粗略的了解
在此先感谢您的帮助! (希望这很容易解决!)
更新: 在对 UI Automation Providers 进行进一步挖掘后,似乎所有自定义控件都必须编写以支持 AutomationProperties。当然,与开发人员交谈并非如此。
我会在找到解决方案后 post 提供更多信息。
没有AutomationPeer
供您控制。所以你的 AutomationId
设置没有设置任何东西。
在您的控制代码隐藏中重写 OnCreateAutomationPeer
,如下所示:
protected override AutomationPeer OnCreateAutomationPeer()
{
return new IconLabelButtonAutomationPeer(this);
}
你的新 IconLabelButtonAutomationPeer
看起来像这样:
public class IconLabelButtonAutomationPeer : FrameworkElementAutomationPeer
{
public IconLabelButtonAutomationPeer(IconLabelButton owner)
: base(owner)
{
}
}
我已经为这个问题苦苦思索了 3 天,一直没能找到答案。
我有一个用 WPF (dot Net 4.5) 编写的应用程序,我正在使用 Teststack.White 尝试编写一些自动化 GUI 测试用例。开发人员已将 x:Names 提供给某些控件,它们通过 Inspect/WPF Inspector/Visual UI Automation Verify 显示为 AutomationId 就好了。
还有其他一些隐藏得更深的控件,我的任务是为其提供自动化 ID(主要是作为练习,以便我可以更熟悉后端)。这是我一直在努力反对的地方。
我试过为控件提供 AutomationProperties.AutomationId(和 .Name)属性。我给了 AutomationProperties 一个名称 space 定义。我也确保 SWA.Peers 被引用。
我还没有尝试在 XAML 中使用 属性 设置器,因为它们目前没有多大意义,我希望不需要在 C# 中编写东西来设置它们(如果我这样做,我会这样做,但只是希望)。
我的一位同事坐下来,我们拿出了不暴露自动化 ID 的最低限度的设置 属性(不幸的是,他和其他开发人员都不知道为什么这没有发生)。看起来像:
MainWindow.xaml:
<Window x:Class="TestAutomationUI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common"
Title="Test UI (Pick me)" Height="455.075" Width="525">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/IconLabelButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel x:Name="PresentationRoot">
<common:IconLabelButton x:Name="TestButton" autoProp:AutomationProperties.AutomationId="TestButtonClick" Text="Stuff" Margin="245,0,214.4,0" RenderTransformOrigin="4.648,0.588" Height="32">
</common:IconLabelButton>
</StackPanel>
</Window>
IconLabelButton.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:autoProp="clr-namespace:System.Windows.Automation;assembly=PresentationCore"
xmlns:common="clr-namespace:Asi.Ui.Common">
<Style TargetType="common:IconLabelButton">
<Setter Property="Template" Value="{DynamicResource Asi.Ui.Common.IconLabelButton}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="FontWeight" Value="{DynamicResource Mobius.UI.Resources.Fonts.WeightLight}"/>
<Setter Property="Spacing" Value="10" />
</Style>
<ControlTemplate x:Key="Asi.Ui.Common.IconLabelButton" TargetType="common:IconLabelButton">
<Border Background="{TemplateBinding Background}" Height="30">
<Button Style="{DynamicResource Mobius.UI.Resources.Styles.IconButton}" Margin="0" Padding="0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Left"
Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}" Foreground="{TemplateBinding Foreground}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="22" />
<ColumnDefinition Width="{TemplateBinding Spacing}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="22" Height="22">
<Path Margin="1" Height="20" Width="20" Fill="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" Data="{TemplateBinding Icon}" Stretch="Fill"/>
<Path Margin="1" Height="20" Width="20" Fill="{TemplateBinding AdornerIconFill}" Data="{TemplateBinding AdornerIcon}" Stretch="Fill"/>
</Grid>
<TextBlock Grid.Column="2" Text="{TemplateBinding Text}" VerticalAlignment="Center" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type ContentControl}}}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontWeight="{TemplateBinding FontWeight}"/>
</Grid>
</Button>
</Border>
</ControlTemplate>
</ResourceDictionary>
IconLabelButton.xaml.cs:
using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Asi.Ui.Common
{
public class IconLabelButton : Control
{
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(IconLabelButton), new PropertyMetadata(default(string)));
public static readonly DependencyProperty AdornerIconProperty =
DependencyProperty.Register("AdornerIcon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register("Icon", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(object)));
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(IconLabelButton), new PropertyMetadata(default(ICommand)));
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty IconButtonSizeProperty =
DependencyProperty.Register("IconButtonSize", typeof(GridLength), typeof(IconLabelButton), new PropertyMetadata(default(GridLength)));
public static readonly DependencyProperty AdornerIconFillProperty =
DependencyProperty.Register("AdornerIconFill", typeof(Brush), typeof(IconLabelButton), new PropertyMetadata(default(Brush)));
static IconLabelButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(IconLabelButton), new FrameworkPropertyMetadata(typeof(IconLabelButton)));
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public object AdornerIcon
{
get { return GetValue(AdornerIconProperty); }
set { SetValue(AdornerIconProperty, value); }
}
public object Icon
{
get { return GetValue(IconProperty); }
set { SetValue(IconProperty, value); }
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public object CommandParameter
{
get { return GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public GridLength Spacing
{
get { return (GridLength)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
public GridLength IconButtonSize
{
get { return (GridLength)GetValue(IconButtonSizeProperty); }
set { SetValue(IconButtonSizeProperty, value); }
}
public Brush AdornerIconFill
{
get { return (Brush)GetValue(AdornerIconFillProperty); }
set { SetValue(AdornerIconFillProperty, value); }
}
}
}
如果这是一个简单的问题(或者如果我问的不对),我深表歉意。我是一个入门级的程序员,对WPF/XAML.
只有粗略的了解在此先感谢您的帮助! (希望这很容易解决!)
更新: 在对 UI Automation Providers 进行进一步挖掘后,似乎所有自定义控件都必须编写以支持 AutomationProperties。当然,与开发人员交谈并非如此。
我会在找到解决方案后 post 提供更多信息。
没有AutomationPeer
供您控制。所以你的 AutomationId
设置没有设置任何东西。
在您的控制代码隐藏中重写 OnCreateAutomationPeer
,如下所示:
protected override AutomationPeer OnCreateAutomationPeer()
{
return new IconLabelButtonAutomationPeer(this);
}
你的新 IconLabelButtonAutomationPeer
看起来像这样:
public class IconLabelButtonAutomationPeer : FrameworkElementAutomationPeer
{
public IconLabelButtonAutomationPeer(IconLabelButton owner)
: base(owner)
{
}
}