요소 트리에 없는 개체 요소 초기화
업데이트: 2007년 11월
WPF(Windows Presentation Foundation) 초기화의 몇 가지 측면은 일반적으로 논리 트리 또는 시각적 트리에 연결되는 요소에 의존하는 프로세스로 지연됩니다. 이 항목에서는 두 트리에 연결되지 않는 요소를 초기화하기 위해 필요할 수 있는 단계를 설명합니다.
이 항목에는 다음 단원이 포함되어 있습니다.
- 요소 및 논리 트리
- 관련 항목
요소 및 논리 트리
코드에서 WPF(Windows Presentation Foundation) 클래스의 인스턴스를 만들 때 WPF(Windows Presentation Foundation) 클래스에 대한 개체 초기화의 몇 가지 측면은 클래스 생성자 호출 시 실행되는 코드의 일부가 아님을 알아 두어야 합니다. 특히 컨트롤 클래스의 경우 해당 컨트롤의 시각적 표현 대부분은 생성자에 정의되지 않고 컨트롤의 템플릿에 의해 정의됩니다. 템플릿의 소스는 다양할 수 있지만 대부분의 경우 템플릿은 테마 스타일에서 가져옵니다. 템플릿은 실제로 런타임에 바인딩됩니다. 즉, 컨트롤 레이아웃 준비가 될 때까지는 필요한 템플릿이 해당 컨트롤에 연결되지 않습니다. 또한 컨트롤은 루트에서 렌더링 화면에 연결되는 논리 트리에 연결되기 전까지는 레이아웃 준비가 되지 않습니다. 모든 자식 요소의 렌더링을 논리 트리에 정의된 대로 시작하는 것은 루트 수준 요소입니다.
시각적 트리도 이 프로세스에 참가합니다. 템플릿을 통하는 시각적 트리의 일부인 요소도 연결되기 전까지 완전히 인스턴스화되지 않습니다.
이 동작의 결과로 요소의 완성된 시각적 특성에 의존하는 특정 작업에서 추가적인 단계를 필요로 하게 됩니다. 이에 대한 예로 생성되었지만 아직 트리에 연결되지 않은 클래스의 시각적 특성을 가져오려고 하는 경우를 생각해 볼 수 있습니다. 예를 들어 RenderTargetBitmap에서 Render를 호출하려고 할 때 전달 중인 시각적 표시가 트리에 연결되지 않은 요소인 경우, 해당 요소는 추가적인 초기화 단계가 완료되어야 시각적으로 완성됩니다.
BeginInit 및 EndInit를 사용하여 요소 초기화
WPF의 다양한 클래스가 ISupportInitialize 인터페이스를 구현합니다. 인터페이스의 BeginInit 및 EndInit 메서드를 사용하여 초기화 단계(예: 렌더링에 영향을 주는 속성 값 설정)가 포함된 코드 영역을 표시합니다. 시퀀스에서 EndInit가 호출된 뒤에는 레이아웃 시스템에서 요소를 처리하고 암시적 스타일을 찾을 수 있습니다.
속성을 설정하는 요소가 FrameworkElement 또는 FrameworkContentElement 파생 클래스인 경우 ISupportInitialize로 캐스팅하는 대신 BeginInit 및 EndInit의 클래스 버전을 호출할 수 있습니다.
샘플 코드
다음 예제는 느슨한 XAML 파일의 렌더링 API 및 XamlReader.Load(Stream)를 사용하여 렌더링에 영향을 주는 속성을 조정하는 다른 API 호출 주위에 BeginInit 및 EndInit를 적절하게 배치하는 방법을 보여 주는 콘솔 응용 프로그램용 샘플 코드입니다.
예제에서는 main 함수만 보여 줍니다. 함수 Rasterize 및 Save(표시되지 않음)는 이미지 처리 및 IO를 처리하는 유틸리티 함수입니다.
[STAThread]
static void Main(string[] args)
{
UIElement e;
string file = Directory.GetCurrentDirectory() + "\\starting.xaml";
using (Stream stream = File.Open(file, FileMode.Open))
{
// loading files from current directory, project settings take care of copying the file
ParserContext pc = new ParserContext();
pc.BaseUri = new Uri(file, UriKind.Absolute);
e = (UIElement)XamlReader.Load(stream, pc);
}
Size paperSize = new Size(8.5 * 96, 11 * 96);
e.Measure(paperSize);
e.Arrange(new Rect(paperSize));
e.UpdateLayout();
/*
* Render effect at normal dpi, indicator is the original RED rectangle
*/
RenderTargetBitmap image1 = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96);
Save(image1, "render1.png");
Button b = new Button();
b.BeginInit();
b.Background = Brushes.Blue;
b.Width = b.Height = 200;
b.EndInit();
b.Measure(paperSize);
b.Arrange(new Rect(paperSize));
b.UpdateLayout();
// now render the altered version, with the element built up and initialized
RenderTargetBitmap image2 = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96);
Save(image2, "render2.png");
}