ASP.NET 2.0에서는 이전 버전보다 웹 응용 프로그램에 다양한 사용자 인터페이스를 빌드하기가 훨씬 더 쉬워졌습니다. 마스터 페이지를 사용하면 태그 및 코드의 기존 템플릿을 기반으로 페이지를 작성할 수 있습니다. 또한 ASP.NET 2.0 마법사를 사용하여 탐색 기능을 보다 손쉽게 구현할 수 있습니다. 뿐만 아니라 지난 달에 설명한 사용자 프로필과 같은 기능을 사용하여 ASP.NET 2.0 페이지에 개인 설정을 추가할 수도 있습니다. 이번 달에는 ASP.NET 응용 프로그램을 보다 손쉽게 구현할 수 있도록 하는 또 다른 기능인 테마에 대해 살펴보겠습니다. 이 기능을 사용하면 최소한의 작업으로 컨트롤 페이지의 스킨을 지정하고 시각적인 일관성을 유지할 수 있습니다. 여기서 사용된 버전은 ASP.NET 2.0의 베타 릴리스이므로 설명되는 일부 세부 사항은 최종 릴리스에서 변경될 수 있습니다.
페이지 테마
ASP.NET 2.0 테마의 장점은 Windows XP 테마처럼 최소한의 변경 내용을 적용하여 페이지의 모양을 대폭 변경시킬 수 있다는 것입니다. 테마가 지정된 컨트롤에서는 시각적 속성을 한 번에 설정하고 변경할 수 있습니다. 또한 컨트롤에서 템플릿을 지원하는 경우 ASP.NET 테마를 사용하여 스킨이 지정된 컨트롤을 만들 수 있습니다. 이에 대해서는 잠시 후 다시 설명하겠습니다.
테마는 다양한 방법으로 설정할 수 있는 페이지 클래스의 특성입니다. 테마가 설정되면 페이지의 모든 컨트롤이 테마에 정의된 시각적 설정에 따라 렌더링됩니다. 테마를 사용하면 ASPX 코드에서 스타일 태그를 분리할 수 있으므로 컨트롤의 스타일 및 주변 그래픽에 신경 쓰지 않고 페이지를 작성할 수 있습니다. 디자이너는 나중에 이 페이지에 대한 테마를 만들 수 있습니다.
ASP.NET 2.0에서 테마는 모두 지정된 폴더에 설치된 여러 가지 파일로 구성됩니다. 폴더 이름은 테마 이름에 따라 결정됩니다. 폴더에는 스킨 파일, CSS 파일을 비롯하여 선택적으로 이미지 하위 폴더나 XSLT 및 텍스트 파일 같은 기타 보조 파일 등의 몇 가지 파일 형식이 있을 수 있습니다. 그림 1에서는 이러한 폴더 구조의 예를 보여 줍니다. 그림에 표시된 테마인 SmokeAndGlass는 원래 ASP.NET 2.0 베타 1에 포함되어 있었지만 나중에 제거되었습니다. 하지만 필자는 백업 파일을 만들어 참조용으로 보관하고 있습니다.

그림 1 ASP.NET 2.0의 사용자 지정 테마
응용 프로그램에서 테마 폴더를 인식하도록 하려면 테마 폴더를 응용 프로그램 루트 아래의 App_Themes 폴더 아래 또는 전역 폴더에 두어야 합니다. 응용 프로그램 루트의 App_Themes 폴더 아래에 있는 테마에는 특정 응용 프로그램에서만 사용할 수 있는 로컬 테마가 있습니다. 전역 테마는 다음 경로 아래에 있는 하위 디렉터리에 포함되어 있습니다.
%WINDOWS%\Microsoft.NET\Framework\[version]\ ASP.NETClientFiles\Themes[version] 자리 표시자는 설치한 ASP.NET 2.0 빌드의 버전 번호를 나타냅니다. 베타 2의 경우 버전 번호는 v2.0.50215입니다. 베타 2 이후의 릴리스를 설치한 경우에는 버전 번호가 다릅니다.
테마 내부 사항
스킨은 .aspx 파일에 있는 것과 같은 컨트롤 정의로 구성된 태그 파일입니다. 스킨 파일을 만드는 한 가지 방법은 임시 페이지를 만들어 컨트롤을 추가하고 적절히 스타일을 지정하는 것입니다. 이 작업을 완료하면 컨트롤 파일의 태그 소스를 스킨 파일에 복사하여 붙여넣기만 하면 됩니다(그림 2 참조). 이 때 태그에서 각 컨트롤의 ID 속성을 제거해야 합니다.
스킨에는 필요한 만큼 많은 컨트롤에 대한 표준 정의가 포함되어 있습니다. 컨트롤마다 여러 개의 스킨을 정의할 수도 있습니다. 이 경우 컨트롤 정의에 SkinID라는 별도의 특성을 추가합니다. SkinID 특성은 컨트롤 스킨의 이름을 지정하고 컨트롤에서 런타임에 해당 템플릿을 선택할 수 있도록 합니다. .aspx 페이지에 있는 다음 GridView 단편을 생각해 봅시다.
<asp:GridView runat="server" id="grid" skinID="Classic" />SkinID 특성은 바인딩된 테마에서 지정된 스킨이 있는 경우 이를 선택합니다. 지정된 스킨 ID가 컨트롤의 기존 스킨과 일치하지 않는 경우 Visual Studio 2005에서 경고 메시지가 나타나고 스킨 ID가 무시되어 테마가 없는 컨트롤이 표시됩니다.
테마는 CSS 파일 없이도 존재할 수 있으며 반대의 경우도 물론 마찬가지입니다. 스킨 파일 자체는 CSS에 포함된다기보다 컨트롤 속성 집합에 포함되며, 일반 렌더링처럼 태그 요소의 인라인 CSS가 됩니다.
스킨 파일에는 AllowPaging 같은 동작 속성을 넣지 않는 것이 좋은 코딩 습관입니다. 하지만 이는 권장 사항일 뿐으로, 스킨 파일에 AllowPaging을 설정해도 올바르게 작동합니다. 그러나 이처럼 스킨에 동작 속성을 저장하면 스타일과 동작 간의 논리적인 구분을 위반하게 됩니다. 또한 테마가 지원될 수 있는 속성을 지시하는 것은 컨트롤이라는 점에 유의해야 합니다.
컨트롤 스킨 지정
테마를 페이지에 바인딩하려면 일반적으로 @Page 지시문의 Theme 특성을 사용합니다.
<% @Page ... Theme="SmokeAndGlass" %>또한 이 설정을 폴더별 Web.config 파일로 이동하여 지정된 폴더의 모든 페이지에 테마를 선언적으로 바인딩할 수 있습니다.
<pages theme="SmokeAndGlass" />
테마는 스타일시트 테마나 사용자 지정 테마의 두 가지 다른 방법으로 페이지에 바인딩할 수 있습니다. 스타일시트 테마는 개발자가 스타일을 한 위치로 요약할 수 있도록 하는 방식으로 디자이너가 지원되는 모방 CSS입니다. 특정 컨트롤의 경우 컨트롤에서 스타일을 직접 다시 정의할 수 있습니다. 이러한 점과 사용하는 키워드가 다르다는 점을 제외하면, 나머지 차이는 적용 시기뿐입니다. Theme 특성을 사용하는 경우에는 사용자 지정 테마를 바인딩하므로 컨트롤의 선언적 특성을 처리한 후에 ASP.NET 런타임에서 테마의 설정을 적용하게 됩니다. 스타일시트 테마는 다음과 같이 Stylesheet 특성을 통해 바인딩됩니다.
<% @Page ... StylesheetTheme="SmokeAndGlass" %>이 경우 테마는 선언적 특성이 처리되기 전에 적용됩니다. 차이점을 명확하게 이해하기 위해 다음 태그를 살펴보겠습니다.
<!-- In the skin file --> <asp:DataGrid runat="server" backcolor="red" /> <!-- In the page --> <asp:DataGrid runat="server" backcolor="yellow" />컨트롤이 사용자 지정 테마에 바인딩된 페이지에 속하는 경우, 표는 테마에 설정된 것처럼 배경색이 빨간색으로 표시됩니다. 페이지의 스타일이 스타일시트 테마를 사용하여 지정된 경우, 테마에 설정된 색상과 관계없이 노란색이 표의 배경색이 됩니다. 또한 테마를 통해 설정된 속성은 필요한 경우 Page_Load 이벤트를 처리하여 프로그래밍 방식으로 다시 정의할 수 있습니다.
GridView 컨트롤에서는 컨트롤이 빈 데이터 소스에 바인딩될 때 사용될 태그를 지정할 수 있도록 EmptyDataTemplate 속성을 지원합니다.
<asp:GridView ...>
...
<EmptyDataTemplate>
<table style="border:solid 1px black"><tr><td>
<img runat="server" align="absmiddle" src="images/critical.gif">
<b>Hello!</b><br>I'm a <b>GridView</b> control.
Unfortunately, though, at this time I have no data to display.
</td></tr></table>
</EmptyDataTemplate>
</asp:GridView>>(참고: 프로그래머 코멘트는 샘플 프로그램 파일에는 영문으로 제공되며 기사에는 설명을 위해 번역문으로 제공됩니다.)
critical.gif 이미지가 테마 폴더 아래의 Images 폴더에서 로드됩니다(그림 1 참조). 그림 3에서는 스킨이 다르게 지정된 동일한 표 컨트롤을 보여 줍니다. 이 그림에서는 같은 테마에서 별개의 스킨에 바운딩된 표를 보여 주지만, 두 스킨을 별개의 테마 파일로 이동하는 작업은 간단합니다.

그림 3 두 가지 방식으로 스킨이 지정된 빈 GridView 컨트롤
특수 테마 기능
테마가 개별 페이지에 필요한 경우 이를 프로그래밍 방식으로 로드하는 것은 매우 간단합니다. 즉, Page 클래스의 Theme 속성을 테마의 이름을 나타내는 문자열로 설정하기만 하면 됩니다. 하지만 스타일시트 테마는 Page 클래스의 StyleSheetTheme 속성을 다시 정의해야 하기 때문에 이러한 방식으로 설정할 수 없습니다. 유일한 방법은 페이지의 PreInit 이벤트에 테마를 설정하는 것입니다. PreInit는 ASP.NET 2.0에 도입된 새 이벤트로, 일반적으로 컨트롤 주기의 첫 번째 지점인 Init 바로 앞에서 발생합니다. 따라서 테마에 대해 속성이 설정되는 지점은 컨트롤에서 속성을 조작하기 전에 적용될 수 있습니다. 이 때 PreInit가 호출되고 페이지의 컨트롤 트리는 이미 빌드되어 있지만 개별 컨트롤의 트리는 빌드되지 않습니다.
PreInit 이벤트에 연결하여 미리 결정된 테마 이름이나 사용자의 프로필, 드롭다운 목록, 쿼리 문자열 또는 다른 장소의 번호 같은 외부 영역에서 가져온 테마 이름으로 테마를 설정할 수 있습니다. 다음은 페이지에 테마를 동적으로 로드하는 유용한 코드 패턴입니다.
Sub Page_PreInit(ByVal sender As Object, ByVal e As EventArgs)
Dim theme As String = GetThemeToApply();
If theme = "" Then Return
Me.Theme = theme
End Sub
사용자 지정 컨트롤이 @Register 지시문을 통해 스킨 파일에 적절히 등록되어 있거나 구성 파일에 등록되어 있으면 테마는 사용자 지정 컨트롤의 스타일을 지정하는 데에도 사용될 수 있습니다.EnableTheming 속성이 false로 설정되어 있지 않는 한(기본값은 true) 컨트롤은 관련 테마에 의해 영향을 받게 됩니다. 컨트롤을 디자인할 때 속성에 Themeable 특성을 적용하고 false로 설정하면 테마 적용을 방지할 수 있습니다.
Public Class MyControl
Inherits WebControl
<Themeable(false)>
Public Property TextFont As Font
...
End Property
End Class
이러한 테마 적용 방지는 속성을 프로그래밍 방식으로 설정해야 하거나, 선언적으로 설정하더라도 항상 개발자나 페이지 코드를 통해 속성을 제어해야 하는 컨트롤에 주로 사용됩니다. 물론 스타일과 관계가 없거나 DataSourceID 같이 보안에 민감한 속성에는 테마를 지정할 수 없습니다. 다른 사람이 테마를 통해 컨트롤의 DataSourceID를 변경할 수 있게 하려는 경우는 없을 것입니다.
요약
테마와 관련된 정보는 SkinID의 프로그래밍 방식 설정, 테마 및 스타일시트가 동적 컨트롤과 상호 작용하는 방법 등과 같이 여기서 설명한 것보다 훨씬 많습니다. 그러나 이 둘러보기를 통해 이러한 새로운 기능이 얼마나 유용한지를 이해하는 데 도움이 되었기를 바랍니다. 개인 설정은 사용자에게 중요한 역할을 하지만 응용 프로그램 디자이너가 유연성과 구성 가능성이 보다 높은 프레임워크를 만드는 데에도 도움이 됩니다. 스킨과 테마는 개인 설정과 사용자 지정을 보다 손쉽게 수행할 수 있도록 해 주는 ASP.NET 2.0의 편리한 기능입니다.
Dino에게 질문이나 의견이 있으면 cutting@microsoft.com.으로 보내시기 바랍니다.