XAML 이름 범위

XAML 이름 범위는 XAML에서 정의한 개체 이름과 해당 인스턴스 이름 간의 관계를 저장합니다. 이 개념은 다른 프로그래밍 언어 및 기술에서 이름 범위라는 용어의 더 넓은 의미와 유사합니다.

XAML 이름 범위 정의 방법

XAML 이름 범위의 이름은 사용자 코드가 XAML에서 처음 선언된 개체를 참조할 수 있게 합니다. XAML 구문 분석의 내부 결과는 런타임이 이러한 개체가 XAML 선언에서 가진 관계의 일부 또는 전부를 유지하는 개체 집합을 만드는 것입니다. 이러한 관계는 기본 생성된 개체의 특정 개체 속성으로 포함되거나 프로그래밍 모델 API의 유틸리티 메서드에 노출됩니다.

XAML 이름 범위에서 이름의 가장 일반적인 사용은 부분 클래스 템플릿에서 생성된 InitializeComponent 메서드와 결합된 프로젝트 빌드 작업으로 태그 컴파일 패스에 의해 활성화되는 개체 인스턴스에 대한 직접 참조입니다.

런타임에 유틸리티 메서드 FindName 을 사용하여 XAML 태그의 이름으로 정의된 개체에 대한 참조를 반환할 수도 있습니다.

빌드 작업 및 XAML에 대한 자세한 정보

기술적으로 발생하는 일은 XAML 자체에서 코드 숨김에 대해 정의한 부분 클래스와 XAML이 함께 컴파일되는 동시에 태그 컴파일러 통과를 거칩니다. 태그에 정의된 Name 또는 x:Name 특성 이 있는 각 개체 요소는 XAML 이름과 일치하는 이름을 가진 내부 필드를 생성합니다. : 이 필드는 처음에는 비어 있습니다. 그런 다음 클래스는 모든 XAML이 로드된 후에만 호출되는 InitializeComponent 메서드를 생성합니다. InitializeComponent 논리 내에서 각 내부 필드는 해당하는 이름 문자열에 대한 FindName 반환 값으로 채워집니다. 컴파일 후 Windows 런타임 앱 프로젝트의 /obj 하위 폴더에 있는 각 XAML 페이지에 대해 생성된 ".g"(생성된) 파일을 확인하여 이 인프라를 직접 관찰할 수 있습니다. 필드 및 InitializeComponent 메서드를 반영하거나 인터페이스 언어 콘텐츠를 검사하는 경우 결과 어셈블리의 멤버로 볼 수도 있습니다.

특히 C++/CX 앱의 경우 x:Name 참조에 대한 지원 필드는 XAML 파일 또는 페이지의 루트 요소에 대해 만들어지지 않습니다. C++/CX 코드 숨김에서 루트 개체를 참조해야 하는 경우 다른 API 또는 트리 순회를 사용합니다. 예를 들어 알려진 명명된 자식 요소에 대해 FindName을 호출한 다음 Parent를 호출할 수 있습니다.

XamlReader.Load를 사용하여 런타임에 개체 만들기

XAML은 초기 XAML 원본 구문 분석 작업과 유사하게 동작하는 XamlReader.Load 메서드에 대한 문자열 입력으로 사용할 수도 있습니다. XamlReader.Load 는 런타임에 연결이 끊긴 새 개체 트리를 만듭니다. 그런 다음 연결이 끊긴 트리를 기본 개체 트리의 특정 지점에 연결할 수 있습니다. 만든 개체 트리를 Children과 같은 콘텐츠 속성 컬렉션에 추가하거나 개체 값을 사용하는 다른 속성(예: Fill 속성 값에 대한 ImageBrush 로드)을 설정하여 명시적으로 연결해야 합니다.

XamlReader.Load의 XAML 이름 범위 의미

XamlReader.Load에서 만든 새 개체 트리에 의해 정의된 예비 XAML 이름 범위는 제공된 XAML에서 정의된 이름을 고유성으로 평가합니다. 제공된 XAML의 이름이 이 시점에서 내부적으로 고유하지 않은 경우 XamlReader.Load 는 예외를 throw합니다. 연결이 끊긴 개체 트리는 기본 애플리케이션 개체 트리에 연결된 경우 XAML 이름 범위와 기본 애플리케이션 XAML 이름 범위 병합을 시도하지 않습니다. 트리를 연결한 후 앱에는 통합 개체 트리가 있지만 해당 트리 내에는 개별 XAML 이름 범위가 있습니다. 나누기는 개체 간의 연결 지점에서 발생하며, 여기서 일부 속성을 XamlReader.Load 호출에서 반환된 값으로 설정합니다.

별개의 XAML 이름 범위와 연결이 끊긴 XAML 이름 범위의 복잡한 점은 FindName 메서드 및 직접 관리되는 개체 참조에 대한 호출이 더 이상 통합된 XAML 이름 범위에 대해 작동하지 않는다는 것입니다. 대신 FindName이 호출되는 특정 개체는 범위를 의미하며 범위는 호출 개체가 있는 XAML 이름 범위입니다. 직접 관리되는 개체 참조 사례에서 범위는 코드가 있는 클래스에 의해 암시됩니다. 일반적으로 앱 콘텐츠의 "page"의 런타임 상호 작용에 대한 코드 숨김은 루트 "page"를 백업하는 부분 클래스에 있으므로 XAML 이름 범위는 루트 XAML 이름 범위입니다.

FindName을 호출하여 루트 XAML 이름 범위에서 명명된 개체를 가져오는 경우 메서드는 XamlReader.Load에서 만든 불연속 XAML 이름 범위에서 개체를 찾을 수 없습니다. 반대로 불연속 XAML 이름 범위에서 가져온 개체에서 FindName을 호출하는 경우 메서드는 루트 XAML 이름 범위에서 명명된 개체를 찾을 수 없습니다.

이 개별 XAML 이름 범위 문제는 FindName 호출을 사용할 때 XAML 이름 범위에서 이름으로 개체를 찾는 데만 영향을 줍니다.

다른 XAML 이름 범위에 정의된 개체에 대한 참조를 얻으려면 다음과 같은 몇 가지 기술을 사용할 수 있습니다.

  • 개체 트리 구조에 있는 것으로 알려진 부모 및/또는 컬렉션 속성(예: Panel.Children에서 반환된 컬렉션)을 사용하여 개별 단계로 전체 트리를 안내합니다.
  • 불연속 XAML 이름 범위에서 호출하고 루트 XAML 이름 범위를 원하는 경우 항상 현재 표시된 기본 창에 대한 참조를 쉽게 얻을 수 있습니다. 호출 Window.Current.Content을 사용하여 현재 애플리케이션 창에서 시각적 루트(콘텐츠 원본이라고도 하는 루트 XAML 요소)를 한 줄의 코드 형태로 가져올 수 있습니다. 그런 다음 FrameworkElement 캐스팅하고 이 범위에서 FindName을 호출할 수 있습니다.
  • 루트 XAML 이름 범위에서 호출하고 불연속 XAML 이름 범위 내에서 개체를 원하는 경우 가장 좋은 방법은 코드에서 미리 계획하고 XamlReader.Load에서 반환한 다음 기본 개체 트리에 추가된 개체에 대한 참조를 유지하는 것입니다. 이 개체는 이제 불연속 XAML 이름 범위 내에서 FindName을 호출하는 데 유효한 개체입니다. 이 개체를 전역 변수로 사용할 수 있도록 유지하거나 메서드 매개 변수를 사용하여 전달할 수 있습니다.
  • 시각적 트리를 검사하여 이름 및 XAML 이름 범위 고려 사항을 완전히 방지할 수 있습니다. VisualTreeHelper API를 사용하면 위치 및 인덱스에 따라 부모 개체 및 자식 컬렉션 측면에서 시각적 트리를 트래버스할 수 있습니다.

템플릿의 XAML 이름 범위

XAML의 템플릿은 간단한 방법으로 콘텐츠를 다시 사용하고 다시 적용하는 기능을 제공하지만 템플릿에는 템플릿 수준에서 정의된 이름의 요소가 포함될 수도 있습니다. 이런 템플릿은 한 페이지에서 여러 번 사용될 수 있기 때문에 이러한 이유로 템플릿은 스타일 또는 템플릿이 적용되는 포함하는 페이지와 독립적으로 고유한 XAML 이름 범위를 정의합니다. 다음 예제를 고려해 보세요.

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  >
  <Page.Resources>
    <ControlTemplate x:Key="MyTemplate">
      ....
      <TextBlock x:Name="MyTextBlock" />
    </ControlTemplate>
  </Page.Resources>
  <StackPanel>
    <SomeControl Template="{StaticResource MyTemplate}" />
    <SomeControl Template="{StaticResource MyTemplate}" />
  </StackPanel>
</Page>

여기에서는 두 개의 컨트롤에 동일한 템플릿이 적용됩니다. 템플릿에 개별 XAML 이름 범위가 없으면 템플릿에 사용된 "MyTextBlock" 이름 때문에 XAML 이름 범위내에서 이름 충돌이 발생합니다. 템플릿의 각 인스턴스에는 고유한 XAML 이름 범위가 있으므로 이 예제에서 인스턴스화된 각 템플릿의 XAML 이름 범위에는 정확하게 하나의 이름만 포함됩니다. 그러나 루트 XAML 이름 범위에는 두 템플릿의 이름이 포함되지 않습니다.

별도의 XAML 이름 범위 때문에 템플릿이 적용되는 페이지의 범위에서 템플릿 내에서 명명된 요소를 찾으려면 다른 기술이 필요합니다. 개체 트리의 일부 개체에서 FindName을 호출하는 대신 먼저 템플릿이 적용된 개체를 가져온 다음 GetTemplateChild를 호출합니다. 컨트롤 작성자가 적용된 템플릿에서 명명된 특정 요소가 컨트롤 자체로 정의되는 동작의 대상이 되는 규칙을 생성하려는 경우 컨트롤 구현 코드의 GetTemplateChild 메서드를 사용할 수 있습니다. GetTemplateChild 메서드는 보호되어 있으므로 컨트롤 작성자만 액세스할 수 있습니다. 또한 파트 및 템플릿 파트의 이름을 지정하고 이를 컨트롤 클래스에 적용된 특성 값으로 보고하기 위해 컨트롤 작성자가 따라야 하는 규칙이 있습니다. 이 기술을 사용하면 다른 템플릿을 적용하려는 사용자를 제어하기 위해 중요한 부분의 이름을 검색할 수 있습니다. 이 경우 컨트롤 기능을 기본 위해 명명된 부분을 바꿔야 합니다.