Share via


WPF 사용자 지정 컨트롤의 UI 자동화

업데이트: 2008년 7월

Microsoft UI 자동화는 자동화 클라이언트가 다양한 플랫폼 및 프레임워크의 사용자 인터페이스를 검사하거나 운영하는 데 사용할 수 있는 일반화된 단일 인터페이스를 제공합니다. UI 자동화를 통해 품질 보증(테스트) 코드와 화면 판독기 같은 내게 필요한 옵션 지원 응용 프로그램은 사용자 인터페이스 요소를 검사하고 다른 코드에서 이러한 요소를 사용하여 사용자 상호 작용을 시뮬레이션할 수 있습니다. 모든 플랫폼에서의 UI 자동화에 대한 자세한 내용은 액세스 가능성을 참조하십시오.

이 항목에서는 WPF 응용 프로그램에서 실행되는 사용자 지정 컨트롤의 서버측 UI 자동화 공급자를 구현하는 방법에 대해 설명합니다. WPF는 사용자 인터페이스 요소 트리와 나란히 존재하는 피어 자동화 개체 트리를 통해 UI 자동화를 지원합니다. 내게 필요한 옵션 기능을 제공하는 테스트 코드 및 응용 프로그램은 자동화 피어 개체를 직접 사용하거나(in-process 코드의 경우) UI 자동화에서 제공하는 일반화된 인터페이스를 통해 사용할 수 있습니다.

이 항목에는 다음 단원이 포함되어 있습니다.

  • 자동화 피어 클래스
  • 기본 제공 자동화 피어 클래스
  • 파생 피어의 보안 고려 사항
  • 피어 탐색
  • 파생 피어 내에서의 사용자 지정
  • 관련 항목

자동화 피어 클래스

WPF 컨트롤은 AutomationPeer에서 파생되는 피어 클래스 트리를 통해 UI 자동화를 지원합니다. 규칙에 따라 피어 클래스 이름은 컨트롤 클래스 이름으로 시작해서 "AutomationPeer"로 끝납니다. 예를 들어 ButtonAutomationPeerButton 컨트롤 클래스의 피어 클래스입니다. 피어 클래스는 UI 자동화 컨트롤 형식과 거의 동일하지만 WPF 요소에 한정됩니다. UI 자동화 인터페이스를 통해 WPF 응용 프로그램에 액세스하는 자동화 코드는 자동화 피어를 직접 사용하지 않지만 같은 프로세스 공간 내의 자동화 코드는 자동화 피어를 직접 사용할 수 있습니다.

기본 제공 자동화 피어 클래스

요소가 사용자의 인터페이스 작업을 허용하거나 화면 판독기 응용 프로그램 사용자에게 필요한 정보가 요소에 포함된 경우 요소가 자동화 피어 클래스를 구현합니다. 일부 WPF 시각적 요소에는 자동화 피어가 없습니다. 자동화 피어를 구현하는 클래스의 몇 가지 예로는 Button, TextBoxLabel이 있습니다. 자동화 피어를 구현하지 않는 클래스의 예로는 Decorator에서 파생되는 Border 같은 클래스와 Panel에 기반을 두는 GridCanvas 같은 클래스가 있습니다.

기본 Control 클래스에는 해당 피어 클래스가 없습니다. Control에서 파생되는 사용자 지정 컨트롤에 해당하는 피어 클래스가 필요한 경우 FrameworkElementAutomationPeer에서 사용자 지정 피어 클래스를 파생시켜야 합니다.

파생 피어의 보안 고려 사항

자동화 피어는 부분 신뢰 환경에서 실행되어야 합니다. UIAutomationClient 어셈블리의 코드는 부분 신뢰 환경에서 실행되도록 구성되어 있지 않으므로 자동화 피어 코드가 이 어셈블리를 참조하면 안 됩니다. 대신 UIAutomationTypes 어셈블리의 클래스를 사용해야 합니다. 예를 들어 UIAutomationTypes 어셈블리의 AutomationElementIdentifiers 클래스를 사용해야 합니다. 이 클래스는 UIAutomationClient 어셈블리의 AutomationElement 클래스에 해당합니다. 자동화 피어 코드에서는 UIAutomationTypes 어셈블리를 참조하는 것이 안전합니다.

피어 탐색

자동화 피어를 찾은 후 in-process 코드는 개체의 GetChildrenGetParent 메서드를 호출하여 피어 트리를 탐색할 수 있습니다. 컨트롤 내에서 WPF 요소 간의 탐색은 피어의 GetChildrenCore 메서드 구현을 통해 지원됩니다. UI 자동화 시스템은 이 메서드를 호출하여 컨트롤 내에 포함된 하위 요소(예: 목록 상자의 목록 항목) 트리를 빌드합니다. 기본 UIElementAutomationPeer.GetChildrenCore 메서드는 요소의 시각적 트리를 이동하여 자동화 피어 트리를 빌드합니다. 사용자 지정 컨트롤은 이 메서드를 재정의하여 자식 요소를 자동화 클라이언트에 노출한 다음 정보를 전달하거나 사용자 상호 작용을 허용하는 요소의 자동화 피어를 반환합니다.

파생 피어 내에서의 사용자 지정

UIElementContentElement에서 파생되는 모든 클래스에는 OnCreateAutomationPeer라는 보호된 가상 메서드가 포함되어 있습니다. WPF는 OnCreateAutomationPeer를 호출하여 각 컨트롤에 대한 자동화 피어 개체를 가져옵니다. 자동화 코드에서는 피어를 사용하여 컨트롤의 특성 및 기능에 대한 정보를 가져오고 대화형 사용자 인터페이스를 시뮬레이션할 수 있습니다. 자동화를 지원하는 사용자 지정 컨트롤은 OnCreateAutomationPeer를 재정의하고 AutomationPeer에서 파생되는 클래스의 인스턴스를 반환해야 합니다. 예를 들어 사용자 지정 컨트롤이 ButtonBase 클래스에서 파생된 경우 OnCreateAutomationPeer에서 반환되는 개체는 ButtonBaseAutomationPeer에서 파생되어야 합니다.

사용자 지정 컨트롤을 구현할 때 기본 자동화 피어 클래스의 "Core" 메서드를 재정의하여 해당 사용자 지정 컨트롤에만 해당하는 고유한 동작을 설명해야 합니다.

OnCreateAutomationPeer 재정의

AutomationPeer에서 직접적 또는 간접적으로 파생되어야 하는 공급자 개체를 반환하도록 사용자 지정 컨트롤에 대해 OnCreateAutomationPeer 메서드를 재정의합니다.

GetPattern 재정의

자동화 피어는 서버측 UI 자동화 공급자의 일부 구현 측면을 단순화하지만 사용자 지정 컨트롤 자동화 피어는 여전히 패턴 인터페이스를 처리해야 합니다. 비 WPF 공급자와 마찬가지로 피어는 IInvokeProvider 같은 System.Windows.Automation.Provider 네임스페이스의 인터페이스 구현을 제공하여 컨트롤 패턴을 지원합니다. 이러한 컨트롤 패턴 인터페이스는 피어 자체로 또는 다른 개체를 사용하여 구현할 수 있습니다. GetPattern의 피어 구현은 지정된 패턴을 지원하는 개체를 반환합니다. UI 자동화 코드는 GetPattern 메서드를 호출하고 PatternInterface 열거형 값을 지정합니다. 재정의한 GetPattern은 지정된 패턴을 구현하는 개체를 반환해야 합니다. 컨트롤에 패턴의 사용자 지정 구현이 없는 경우 기본 형식의 GetPattern 구현을 호출하여 해당 구현을 가져오거나 패턴이 이 컨트롤 형식에서 지원되지 않는 경우 null을 가져올 수 있습니다. 예를 들어 사용자 지정 NumericUpDown 컨트롤을 범위 내의 값으로 설정하여 해당 UI 자동화 피어가 IRangeValueProvider 인터페이스를 구현하도록 할 수 있습니다. 다음 예제에서는 피어의 GetPattern 메서드를 재정의하여 PatternInterface.RangeValue 값에 응답하는 방법을 보여 줍니다.

public override object GetPattern(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.RangeValue)
    {
        return this;
    }
    return base.GetPattern(patternInterface);
}

GetPattern 메서드가 패턴 공급자로 하위 요소를 지정할 수도 있습니다. 다음 코드에서는 ItemsControl이 스크롤 패턴 처리를 해당 내부 ScrollViewer 컨트롤의 피어에 전달하는 방법을 보여 줍니다.

public override object GetPattern(PatternInterface patternInterface)
{
    if (patternInterface == PatternInterface.Scroll)
    {
        ItemsControl owner = (ItemsControl) base.Owner;

        // ScrollHost is internal to the ItemsControl class
        if (owner.ScrollHost != null)
        {
            AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(owner.ScrollHost);
            if ((peer != null) && (peer is IScrollProvider))
            {
                peer.EventsSource = this;
                return (IScrollProvider) peer;
            }
        }
    }
    return base.GetPattern(patternInterface);
}

패턴 처리에 하위 요소를 지정하기 위해 이 코드는 하위 요소 개체를 가져오고 CreatePeerForElement 메서드를 사용하여 피어를 만든 다음 새 피어의 EventsSource 속성을 현재 피어로 설정하고 새 피어를 반환합니다. 하위 요소에 EventsSource를 설정하면 하위 요소가 자동화 피어 트리에 나타나지 않으며 하위 요소에서 발생시킨 모든 이벤트가 EventsSource에 지정된 컨트롤에서 만들어진 것으로 지정됩니다. ScrollViewer 컨트롤은 자동화 트리에 나타나지 않고 이 컨트롤에서 생성되는 스크롤 이벤트가 ItemsControl 개체에서 만들어진 것으로 나타납니다.

"Core" 메서드 재정의

자동화 코드는 피어 클래스의 공용 메서드를 호출하여 컨트롤에 대한 정보를 가져옵니다. 사용자 지정 컨트롤 구현이 기본 자동화 피어 클래스에서 제공하는 것과는 다른 경우 컨트롤에 대한 정보를 제공하려면 이름이 "Core"로 끝나는 각 메서드를 재정의합니다. 다음 예제와 같이 컨트롤에서 최소한 GetClassNameCoreGetAutomationControlTypeCore 메서드를 구현해야 합니다.

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

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

사용자 지정 GetAutomationControlTypeCore 구현은 ControlType 값을 반환하여 컨트롤을 설명합니다. ControlType.Custom을 반환할 수도 있지만 컨트롤을 정확하게 설명하는 보다 구체적인 컨트롤 형식이 있으면 이들 중 하나를 반환해야 합니다. ControlType.Custom의 반환 값을 사용할 경우 공급자가 UI 자동화를 구현하는 데 추가 작업이 필요하며 UI 자동화 클라이언트 제품이 컨트롤 구조, 키보드 상호 작용 및 가능한 컨트롤 패턴을 예상할 수 없습니다.

IsContentElementCoreIsControlElementCore 메서드를 구현하여 컨트롤이 데이터 콘텐츠를 포함하는지, 사용자 인터페이스에서 대화형 역할을 하는지 또는 둘 모두에 해당하는지 여부를 나타냅니다. 두 메서드 모두 기본적으로 true를 반환합니다. 이러한 설정을 통해 화면 판독기 같은 자동화 도구의 유용성이 향상되며, 이러한 메서드를 사용하여 자동화 트리를 필터링할 수 있습니다. GetPattern 메서드가 하위 요소 피어에 패턴 처리를 전달할 경우 하위 요소 피어의 IsControlElementCore 메서드는 자동화 트리에서 하위 요소 피어를 숨기기 위해 false를 반환할 수 있습니다. 예를 들어 ListBox 내의 스크롤은 ScrollViewer에서 처리하고 PatternInterface.Scroll에 대한 자동화 피어는 ListBoxAutomationPeer와 연결된 ScrollViewerAutomationPeerGetPattern 메서드에서 반환합니다. 따라서 ScrollViewerAutomationPeerIsControlElementCore 메서드가 false를 반환하게 되어 ScrollViewerAutomationPeer가 자동화 트리에 나타나지 않습니다.

자동화 피어는 컨트롤에 적절한 기본값을 제공해야 합니다. 사용자 지정 컨트롤을 참조하는 XAML은 AutomationProperties 특성을 포함하여 코어 메서드의 피어 구현을 재정의할 수 있습니다. 예를 들어 다음 XAML은 사용자 지정된 UI 자동화 속성 두 개가 있는 단추를 만듭니다.

<Button AutomationProperties.Name="Special" 
    AutomationProperties.HelpText="This is a special button."/>

패턴 공급자 구현

소유 요소가 Control에서 직접 파생되는 경우 사용자 지정 공급자로 구현된 인터페이스가 명시적으로 선언됩니다. 예를 들어 다음 코드는 범위 값을 구현하는 Control의 피어를 선언합니다.

public class RangePeer1 : FrameworkElementAutomationPeer, IRangeValueProvider { }

소유 컨트롤이 RangeBase 같은 특정 컨트롤 형식에서 파생되는 경우 동등한 파생 피어 클래스에서 피어를 파생시킬 수 있습니다. 이 경우에는 IRangeValueProvider의 기본 구현을 제공하는 RangeBaseAutomationPeer에서 피어를 파생시킬 수 있습니다. 다음 코드에서는 이와 같은 피어의 선언을 보여 줍니다.

public class RangePeer2 : RangeBaseAutomationPeer { }

구현 예제를 보려면 테마 및 UI 자동화 지원이 있는 NumericUpDown 사용자 지정 컨트롤 샘플를 참조하십시오.

이벤트 발생

자동화 클라이언트는 자동화 이벤트를 구독할 수 있습니다. 사용자 지정 컨트롤은 RaiseAutomationEvent 메서드를 호출하여 컨트롤 상태 변경을 보고해야 합니다. 마찬가지로 속성 값이 변경되면 RaisePropertyChangedEvent 메서드를 호출해야 합니다. 다음 코드에서는 컨트롤 코드 내에서 피어 개체를 가져오고 메서드를 호출하여 이벤트를 발생시키는 방법을 보여 줍니다. 최적화 방법으로 코드는 이 이벤트 형식에 대한 수신기가 있는지 여부를 결정합니다. 수신기가 있는 경우에만 이벤트를 발생시키면 불필요한 오버헤드가 방지되고 컨트롤의 응답 성능이 향상됩니다.

if (AutomationPeer.ListenerExists(AutomationEvents.PropertyChanged))
{
    NumericUpDownAutomationPeer peer = 
        UIElementAutomationPeer.FromElement(nudCtrl) as NumericUpDownAutomationPeer;

    if (peer != null)
    {
        peer.RaisePropertyChangedEvent(
            RangeValuePatternIdentifiers.ValueProperty,
            (double)oldValue,
            (double)newValue);
    }
}

참고 항목

작업

테마 및 UI 자동화 지원이 있는 NumericUpDown 사용자 지정 컨트롤 샘플

테스트 스크립트 생성기 샘플

개념

UI 자동화 개요

서버측 UI 자동화 공급자 구현

변경 기록

날짜

변경 내용

이유

2008년 7월

항목이 추가되었습니다.

향상된 기능 관련 정보