C# 为WPF ControlTemplate子级指定唯一名称

C# 为WPF ControlTemplate子级指定唯一名称,c#,wpf,C#,Wpf,在我们的WPF软件中,我们使用了一个ControlTemplate,它定义了一个ToggleButton,使窗口收缩/扩展。ToggleButton的定义如下: 我们正在创建一个自定义的DockPanel,它在右上角包含此按钮。我们的应用程序最多可以同时包含三个DockPanels: 上图显示了每个DockPanel右侧的小矩形 请注意,从定义中可以看出,所有三个矩形都有相同的名称:“PART\u MaximizeToggle”。这会在编写CodedUI程序以自动化测试时造成麻烦。Code

在我们的WPF软件中,我们使用了一个
ControlTemplate
,它定义了一个
ToggleButton
,使窗口收缩/扩展。
ToggleButton
的定义如下:


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

上图显示了每个
DockPanel
右侧的小矩形

请注意,从定义中可以看出,所有三个矩形都有相同的名称:
“PART\u MaximizeToggle”
。这会在编写CodedUI程序以自动化测试时造成麻烦。CodedUI将他们所有的好友姓名捕获为
“PART\u maximitedoggle”
,名称字段为空。
DockPanel
s的位置和顺序可以根据用户的需要而改变

我们如何让CodedUI捕捉到预期点击的准确按钮?我正在考虑使每个切换按钮的
名称
动态化,但针对特定的
DockPanel
进行固定

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

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

公共静态类测试属性
{
私有静态只读字典_计数器=新字典();
公共静态只读DependencyProperty AutoNameProperty=DependencyProperty.RegisterAttached(
“AutoName”、typeof(string)、typeof(TestingProperties)、新PropertyMetadata(默认值(string)、OnAutoNamePropertyChanged));
AutoNamePropertyChanged上的私有静态无效(DependencyObject元素,DependencyPropertyChangedEventArgs)
{
字符串值=(字符串)eventArgs.NewValue;
if(String.IsNullOrWhiteSpace(value))返回;
if(DesignerProperties.GetIsInDesignMode(元素))返回;
如果(!(元素为FrameworkElement))返回;
int指数=0;
如果(!\u计数器容器(值))
_计数器。添加(值、索引);
其他的
索引=++计数器[值];
string name=string.Format(“{0}{1}”,值,索引);
((FrameworkElement)元素)。名称=名称;
((FrameworkElement)元素).RegisterName(名称,元素);
}
公共静态void SetAutoName(DependencyObject元素,字符串值)
{
SetValue(AutoNameProperty,value);
}
公共静态字符串GetAutoName(DependencyObject元素)
{
返回(字符串)元素.GetValue(AutoNameProperty);
}
}
XAML中的用法:


生成的可视化树:

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

公共静态类测试属性
{
私有静态只读字典_计数器=新字典();
公共静态只读DependencyProperty AutoNameProperty=DependencyProperty.RegisterAttached(
“AutoName”、typeof(string)、typeof(TestingProperties)、新PropertyMetadata(默认值(string)、OnAutoNamePropertyChanged));
AutoNamePropertyChanged上的私有静态无效(DependencyObject元素,DependencyPropertyChangedEventArgs)
{
字符串值=(字符串)eventArgs.NewValue;
if(String.IsNullOrWhiteSpace(value))返回;
if(DesignerProperties.GetIsInDesignMode(元素))返回;
如果(!(元素为FrameworkElement))返回;
int指数=0;
如果(!\u计数器容器(值))
_计数器。添加(值、索引);
其他的
索引=++计数器[值];
string name=string.Format(“{0}{1}”,值,索引);
((FrameworkElement)元素)。名称=名称;
((FrameworkElement)元素).RegisterName(名称,元素);
}
公共静态void SetAutoName(DependencyObject元素,字符串值)
{
SetValue(AutoNameProperty,value);
}
公共静态字符串GetAutoName(DependencyObject元素)
{
返回(字符串)元素.GetValue(AutoNameProperty);
}
}
XAML中的用法:


生成的可视化树:


曼弗雷德·拉德维默的解决方案很有用,但使后面的控制代码更难编写

控件的OnApplyTemplate中搜索该模板部分的任何动态代码都将成为一个难题

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

见:

曼弗雷德·拉德维默的解决方案很有用,但使后面的控制代码更难编写

控件的OnApplyTemplate中搜索该模板部分的任何动态代码都将成为一个难题

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

见:

非常有用!我在一个SCADA软件中被阻止了,该软件无法在整个应用程序中管理非唯一名称。非常有用!我在一个SCADA软件中被阻止,该软件无法在整个应用程序中管理非唯一名称。
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);
    }
}