为WPF ControlTemplate子项提供唯一名称

时间:2016-12-02 06:15:21

标签: c# wpf

在我们的WPF软件中,我们使用ControlTemplate来定义导致窗口缩小/扩展的ToggleButtonToggleButton的定义如下:

<ToggleButton ToolTip="Standard/Extended" Grid.Column="0"
    x:Name="PART_MaximizeToggle" VerticalAlignment="Top"
    HorizontalAlignment="Right" Margin="0,5,5,0"
    Width="14" Height="14" Cursor="Hand">

我们正在创建一个自定义DockPanel,其右上角包含此按钮。我们的应用程序最多可同时包含三个DockPanel

DockPanel screenshots

每个DockPanel右侧的小矩形显示在上图中。

从定义中注意,所有三个矩形都具有相同的名称:"PART_MaximizeToggle"。这在编写CodedUI程序以自动化测试时会造成麻烦。 CodedUI将所有FriendlyNames捕获为"PART_MaximizeToggle",其中Name字段为空。 DockPanel的位置和顺序可以根据用户的需要而改变。

如何让CodedUI捕获精确到达预期点击的按钮?我正在考虑让每个切换按钮的Name动态,但针对特定的DockPanel进行修复。

我该怎么做?有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

您可以通过and register自动分配(AttachedProperty)名称,为每个前缀增加一个计数器。 (这只是一个概念证明,你还应该检查名称是否有效)

public static class TestingProperties
{
    private static readonly Dictionary<string, int> _counter = new Dictionary<string, int>();

    public static readonly DependencyProperty AutoNameProperty = DependencyProperty.RegisterAttached(
        "AutoName", typeof(string), typeof(TestingProperties), new PropertyMetadata(default(string), OnAutoNamePropertyChanged));

    private static void OnAutoNamePropertyChanged(DependencyObject element, DependencyPropertyChangedEventArgs eventArgs)
    {
        string value = (string) eventArgs.NewValue;

        if (String.IsNullOrWhiteSpace(value)) return;
        if (DesignerProperties.GetIsInDesignMode(element)) return;
        if (!(element is FrameworkElement)) return;

        int index = 0;
        if (!_counter.ContainsKey(value))
            _counter.Add(value, index);
        else
            index = ++_counter[value];

        string name = String.Format("{0}_{1}", value, index);
        ((FrameworkElement)element).Name = name;
        ((FrameworkElement)element).RegisterName(name, element);
    }

    public static void SetAutoName(DependencyObject element, string value)
    {
        element.SetValue(AutoNameProperty, value);
    }

    public static string GetAutoName(DependencyObject element)
    {
        return (string)element.GetValue(AutoNameProperty);
    }
}

XAML中的用法:

<!-- will be Button_0 -->
<Button namespace:TestingProperties.AutoName="Button"/>

<!-- will be Button_1 -->
<Button namespace:TestingProperties.AutoName="Button"/>

<!-- will be Button_2 -->
<Button namespace:TestingProperties.AutoName="Button"/>

生成的Visual-Tree:

VisualTree of Example

答案 1 :(得分:1)

Manfred Radlwimmer的解决方案非常有用,但却使控制代码变得更加困难。

Controls'OnApplyTemplate中搜索该模板部分的任何动态代码都会变得很痛苦。

另一种方法是使用相同的技巧(生成唯一ID)代替自动化ID,并在测试中使用自动化ID。

请参阅: http://www.jonathanantoine.com/2011/11/03/coded-ui-tests-automationid-or-how-to-find-the-chose-one-control/