다음을 통해 공유


WPF 이름 범위

업데이트: 2007년 11월

이름 범위는 개념인 동시에 XAML 정의 개체 이름과 그에 해당하는 인스턴스 항목 간의 관계를 저장하는 프로그래밍 개체입니다. WPF 관리 코드의 이름 범위는 XAML 응용 프로그램의 페이지를 로드하는 동안 생성됩니다. 프로그램 개체로서의 이름 범위는 INameScope 인터페이스로 정의되고 실용적인 클래스 NameScope로 구현됩니다.

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

  • 로드된 XAML 응용 프로그램의 이름 범위
  • 스타일 및 템플릿의 이름 범위
  • 이름 범위 및 이름 관련 API
  • 관련 항목

로드된 XAML 응용 프로그램의 이름 범위

이름 범위는 페이지가 처리될 때 XAML 페이지의 루트 요소에 생성됩니다. 페이지 내에서 지정된 각 이름은 관련 이름 범위에 추가됩니다. PageWindow 같은 공통 루트 요소는 항상 이름 범위를 제어합니다. 태그에서 FrameworkElement 또는 FrameworkContentElement 같은 요소가 페이지의 루트 요소인 경우 XAML 프로세서는 Page가 이름 범위를 제공할 수 있도록 Page 루트를 암시적으로 추가합니다. 처음에 XAML에서 Name 또는 x:Name 특성을 정의하지 않은 경우에도 이름 범위가 만들어집니다.

한 이름 범위에서 같은 이름을 두 번 사용하려고 하면 예외가 발생합니다. 코드 숨김이 있으며 컴파일된 응용 프로그램의 일부인 XAML의 경우에는 페이지에 대해 생성된 클래스를 만들 때 이러한 예외가 발생합니다.

구문 분석된 요소 트리에 요소 추가

초기 로드 및 처리 후에 요소 트리에 요소를 추가하려면 이름 범위를 정의하는 클래스에 대한 적절한 RegisterName 구현을 호출해야 합니다. 그렇지 않으면 FindName 같은 메서드를 통해 추가된 개체를 이름으로 참조할 수 없습니다 Name 속성(또는 x:Name 특성)을 설정하기만 해서는 해당 이름이 이름 범위에 등록되지 않습니다. 명명된 요소를 이름 범위가 있는 요소 트리에 추가해도 이름이 이름 범위에 등록되지 않습니다. 이름 범위를 중첩시킬 수도 있지만 일반적으로는 루트 요소에 존재하는 이름 범위에 이름을 등록하므로 이름 범위 위치는 동등한 수준의 로드된 XAML 페이지에서 만들어진 이름 범위와 유사합니다. 응용 프로그램 개발자의 경우 가장 일반적인 시나리오는 RegisterName을 사용하여 현재 루트에 있는 이름 범위에 이름을 등록하는 것입니다. RegisterName은 애니메이션으로 실행될 Storyboard를 찾는 중요한 시나리오 중 하나입니다. 자세한 내용은 Storyboard 개요를 참조하십시오. 같은 논리 트리에서 루트 요소 이외의 요소에 대해 RegisterName을 호출하면 루트 요소에 대해 RegisterName을 호출한 것처럼 루트에 가장 가까운 요소에 이름이 등록됩니다.

코드의 이름 범위

응용 프로그램을 프로그래밍 방식으로 만들고 로드한 XAML에서 가져오지 않은 경우 이름 범위를 지원하려면 루트 요소가 INameScope를 구현하거나 FrameworkElement 또는 FrameworkContentElement 파생 클래스여야 합니다.

또한 XAML 프로세서로 로드 및 처리되지 않는 모든 요소에 대해서는 기본적으로 개체의 이름 범위가 만들어지거나 초기화되지 않습니다. 따라서 이후에 이름을 등록하려는 모든 요소에 대해 명시적으로 새 이름 범위를 만들어야 합니다. 요소에 대한 이름 범위를 만들려면 정적 SetNameScope 메서드를 호출합니다. 요소를 dependencyObject 매개 변수로 지정하고 새 NameScope 생성자 호출을 value 매개 변수로 지정합니다.

SetNameScope의 dependencyObject로 제공되는 개체가 INameScope 구현, FrameworkElement 또는 FrameworkContentElement가 아닌 경우에는 자식 요소에 대해 RegisterName을 호출해도 아무런 변화가 없습니다. 새 이름 범위를 명시적으로 만들지 못한 경우 RegisterName을 호출하면 예외가 발생합니다.

코드에서 API 이름 범위를 사용하는 예제에 대해서는 방법: 이름 범위 정의를 참조하십시오.

스타일 및 템플릿의 이름 범위

WPF의 스타일 및 템플릿을 사용하면 직관적인 방식으로 콘텐츠를 다시 사용하고 적용할 수 있지만 템플릿 수준에서 정의된 이름이 있는 요소가 스타일 및 템플릿에 포함될 수 있습니다. 이런 템플릿은 한 페이지에서 여러 번 사용될 수 있기 때문에 스타일 및 템플릿 모두 스타일이나 템플릿이 적용되는 포함 페이지와는 별도로 고유한 이름 범위를 정의합니다.

다음 예제를 참조하십시오.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  >
  <Page.Resources>
    <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type Button}">
      <Border BorderBrush="Red" Name="TheBorder" BorderThickness="2">
        <ContentPresenter/>
      </Border>      
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <Button Template="{StaticResource MyButtonTemplate}">My first button</Button>
    <Button Template="{StaticResource MyButtonTemplate}">My second button</Button>
  </StackPanel>
</Page>

여기에서는 두 개의 단추에 동일한 템플릿이 적용됩니다. 템플릿에 개별 이름 범위가 없으면 템플릿에 사용된 TheBorder 이름 때문에 이름 충돌이 발생합니다. 하지만 템플릿의 개별 인스턴스에는 고유한 이름 범위가 있으므로 이 예제에서 인스턴화된 각 템플릿의 이름 범위에는 정확하게 하나의 이름만 포함됩니다.

스타일도 고유한 이름 범위를 사용하므로 Storyboard의 각 부분에 특정 이름을 할당될 수 있습니다. 이러한 이름을 사용하면 컨트롤 사용자 지정 과정에서 템플릿이 재정의된 경우에도 해당 이름의 요소를 대상으로 하는 특정 동작을 제어할 수 있습니다.

이름 범위가 분리되어 있으므로 템플릿에서 명명된 요소를 찾는 것이 페이지에서 템플릿 형식이 아닌 요소를 찾는 것보다 복잡합니다. 먼저 템플릿이 적용된 컨트롤의 Template 속성 값을 가져와 적용된 템플릿을 확인해야 합니다. 그런 다음 템플릿이 두 번째 매개 변수로 적용된 컨트롤을 전달하여 템플릿 버전의 FindName을 호출합니다.

컨트롤 제작자가 적용된 템플릿에서 명명된 특정 요소가 컨트롤 자체로 정의되는 동작의 대상이 되는 규칙을 생성하려는 경우 컨트롤 구현 코드의 GetTemplateChild 메서드를 사용할 수 있습니다. GetTemplateChild 메서드는 protected로 선언되므로 컨트롤 제작자만 액세스할 수 있습니다.

템플릿 내에서 작업하면서 템플릿이 적용된 이름 범위를 사용해야 하는 경우에는 TemplatedParent를 가져온 다음 거기서 FindName을 호출합니다. 적용된 템플릿의 요소에서 이벤트가 발생되는 이벤트 처리기를 구현하는 경우가 템플릿 내에서 작업하는 예에 해당합니다.

이름 범위 및 이름 관련 API

FrameworkElement에는 FindName, RegisterNameUnregisterName 메서드가 있습니다. 이러한 메서드를 호출하는 요소에 고유한 이름 범위가 있는 경우 요소 메서드는 단순히 이름 범위의 메서드를 호출합니다. 그렇지 않은 경우에는 부모 요소에 고유한 이름 범위가 있는지 확인하며, 이 확인 과정은 이름 범위를 찾을 때까지 재귀적으로 계속됩니다(XAML 프로세서의 동작 때문에 루트에는 반드시 이름 범위가 있음). FrameworkContentElement에도 이와 유사한 동작이 있지만 FrameworkContentElement에는 고유한 이름 범위가 없다는 점이 다릅니다. 따라서 메서드는 FrameworkContentElement에 존재하므로 결국에는 호출을 FrameworkElement 부모 요소로 전달할 수 있습니다.

SetNameScope는 새 이름 범위를 기존 개체에 매핑하는 데 사용됩니다. SetNameScope를 여러 번 호출하여 이름 범위를 다시 설정하거나 지울 수 있지만 일반적인 사용 방법은 아닙니다. 또한 일반적으로 GetNameScope는 코드에서도 잘 사용되지 않습니다.

이름 범위 구현

다음 클래스는 INameScope를 직접 구현합니다.

ResourceDictionary는 사전-해시 테이블 구현이므로 이름 범위 대신 키가 사용됩니다. ResourceDictionary에서 INameScope를 구현하는 유일한 이유는 사용자 코드에서 예외를 발생시켜 실제 이름 범위와 ResourceDictionary의 키 처리 방식을 명확하게 구분할 수 있게 만들고 이름 범위가 부모 요소에 의해 ResourceDictionary에 적용되지 않게 하기 위해서입니다.

FrameworkTemplateStyle은 명시적 인터페이스 정의를 통해 INameScope를 구현합니다. 명시적 구현을 사용하면 INameScope 인터페이스를 통해 이름 범위에 액세스할 때 이러한 이름 범위가 규칙에 따라 작동할 수 있습니다. 그리고 이것이 WPF 내부 프로세스에서 이름 범위가 전달되는 방식입니다. 하지만 FrameworkTemplateStyle에서 직접 INameScope 메서드를 호출해야 하는 경우가 거의 없으므로 명시적 인터페이스 정의는 FrameworkTemplateStyle의 일반적인 API 화면에 속하지 않습니다.

다음 클래스에서는 System.Windows.NameScope 도우미 클래스를 사용하고 NameScope 연결된 속성을 통해 이름 범위 구현을 연결하여 고유한 이름 범위를 정의합니다.

참고 항목

개념

XAML 네임스페이스 및 네임스페이스 매핑

참조

x:Name 특성