2016-11-06 1 views
1

저는 TestStack White (UI Automation)를 사용하여 WPF 기존 응용 프로그램에서 테스트를 자동화하기 시작했습니다. 표준 컨트롤을 사용할 때 모든 것이 잘 동작합니다. 그러나 사용자 정의 컨트롤을 상호 작용할 때 문제가 발생합니다.UI 자동화 및 TestStack White를 사용하려면 사용자 정의 컨트롤을 어떻게 정의해야합니까?

예를 들어, 실제로 TextBlock과 ComboBox 인 LabeledComboBox가 있습니다. 이 작업은 XAML에서 컨트롤 플러스의 ControlTemplate에서 파생 된 클래스로 정의된다

public class LabeledComboBox : Control 
 
{ 
 
    static LabeledComboBox() 
 
    { 
 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledComboBox), new FrameworkPropertyMetadata(typeof(LabeledComboBox))); 
 
    } 
 
}

<local:LabeledComboBox> 
 
    <local:LabeledComboBox.Template> 
 
     <ControlTemplate TargetType="{x:Type local:LabeledComboBox}"> 
 
      <StackPanel> 
 
        <TextBlock Text="Text"/> 
 
        <ComboBox/> 
 
      </StackPanel> 
 
      </ControlTemplate> 
 
    </local:LabeledComboBox.Template> 
 
</local:LabeledComboBox>

이 컨트롤 작동하지만 당신이 실행하는 경우 UI 자동화는 만 확인 UI Automation에 표시되는 부분은 ComboBox이며 TextBlock에 액세스 할 수 없습니다.

그러나 XAML 및 코드 숨김을 사용하여 UserControl로이를 만들면 TextBox와 ComboBox가 UI 자동화에 올바르게 표시됩니다.

내 컨트롤에 대한 AutomationPeer (FrameworkElementAutomationPeer)를 만들려고했지만 지금까지 UI 자동화에서 TextBlock을 볼 수 없었습니다. 흥미로운 결과 중 하나는 FrameworkElementAutomationPeer :: GetChildrenCore()가 TextBlock 및 ComboBox 용으로 2 개의 자동화 피어 목록을 제대로 반환한다는 것입니다.

UI 자동화 및 흰색을 사용하여 제대로 테스트 할 수 있도록 사용자 지정 컨트롤을 어떻게 변경해야합니까?

답변

1

TextBlock (TextBlockAutomationPeer)의 기본 자동화 피어는 UI 트리가 ControlTemplate의 일부인 경우 UI 트리에서 해당 소유자를 제거합니다.

당신은 관련 여기에 코드를 찾을 수 있습니다 :이 같은 코드 https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Automation/Peers/TextBlockAutomationPeer.cs,16e7fab76ffcb40a

override protected bool IsControlElementCore() 
{ 
    // Return true if TextBlock is not part of a ControlTemplate 
    TextBlock tb = (TextBlock)Owner; 
    DependencyObject templatedParent = tb.TemplatedParent; 
    return templatedParent == null || templatedParent is ContentPresenter; // If the templatedParent is a ContentPresenter, this TextBlock is generated from a DataTemplate 
} 
그래서

는,이 문제를 해결하려면, 당신은 ControlTemplate이 아닌 TextBlock을 선언 할 것이다, 또는 해결 방법을 (어려운 일반화하기 전체 응용 프로그램에 ...) :

public class LabeledComboBox : Control 
{ 
    static LabeledComboBox() 
    { 
     DefaultStyleKeyProperty.OverrideMetadata(typeof(LabeledComboBox), new FrameworkPropertyMetadata(typeof(LabeledComboBox))); 
    } 

    // define our own peer 
    protected override AutomationPeer OnCreateAutomationPeer() 
    { 
     return new LabeledComboBoxAutomationPeer(this); 
    } 

    protected class LabeledComboBoxAutomationPeer : FrameworkElementAutomationPeer 
    { 
     public LabeledComboBoxAutomationPeer(LabeledComboBox owner) : base(owner) 
     { 
     } 

     // replace all TextBlockAutomationPeer by our custom peer for TextBlock 
     protected override List<AutomationPeer> GetChildrenCore() 
     { 
      var list = base.GetChildrenCore(); 
      for (int i = 0; i < list.Count; i++) 
      { 
       var tb = list[i] as TextBlockAutomationPeer; 
       if (tb != null) 
       { 
        list[i] = new InteractiveTextBlockAutomationPeer((TextBlock)tb.Owner); 
       } 
      } 
      return list; 
     } 
    } 

    // just do the default stuff, instead of the strange TextBlockAutomationPeer implementation 
    protected class InteractiveTextBlockAutomationPeer : FrameworkElementAutomationPeer 
    { 
     public InteractiveTextBlockAutomationPeer(TextBlock owner) : base(owner) 
     { 
     } 

     protected override AutomationControlType GetAutomationControlTypeCore() 
     { 
      return AutomationControlType.Text; 
     } 

     protected override string GetClassNameCore() 
     { 
      return "TextBlock"; 
     } 
    } 
} 

또 다른 해결책은 TextBlock의에서 파생 자신의 TextBlock의 컨트롤 클래스()를 생성하고 사용자 정의를 반환 OnCreateAutomationPeer을 무시하는 것입니다.

+0

설명 주셔서 감사합니다. 모든 솔루션이 올바르게 작동합니다. 좀 더 많은 정보를 찾았습니다. http://stackoverflow.com/a/2846419/5414769 –

관련 문제