개체 트리에 없는 개체 요소 초기화
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의 클래스 버전을 호출할 수 있습니다.
샘플 코드
다음 예제는 렌더링 API와 느슨한 XAML 파일의 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");
}
<STAThread>
Shared Sub Main(ByVal args() As String)
Dim e As UIElement
Dim _file As String = Directory.GetCurrentDirectory() & "\starting.xaml"
Using stream As Stream = File.Open(_file, FileMode.Open)
' loading files from current directory, project settings take care of copying the file
Dim pc As New ParserContext()
pc.BaseUri = New Uri(_file, UriKind.Absolute)
e = CType(XamlReader.Load(stream, pc), UIElement)
End Using
Dim paperSize As 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
'
Dim image1 As RenderTargetBitmap = Rasterize(e, paperSize.Width, paperSize.Height, 96, 96)
Save(image1, "render1.png")
Dim b As New Button()
b.BeginInit()
b.Background = Brushes.Blue
b.Height = 200
b.Width = b.Height
b.EndInit()
b.Measure(paperSize)
b.Arrange(New Rect(paperSize))
b.UpdateLayout()
' now render the altered version, with the element built up and initialized
Dim image2 As RenderTargetBitmap = Rasterize(b, paperSize.Width, paperSize.Height, 96, 96)
Save(image2, "render2.png")
End Sub
참고 항목
.NET Desktop feedback