준비 사항Silverlight 개발의 기초에서 개발에 필요한 도구와 기술에 대해 설명하고 있습니다.
이벤트 핸들링에서 개체의 이벤트를 처리하는 방법에 대해 설명하고 있습니다.
HTML DOM(Document Object Model)과 JavaScript에 대한 사전 지식이 필요합니다.
http://www.cadvance.org/ 에 HTML부터 XML까지 아주 잘 정리되어 있으니 참고하시기 바랍니다.
예제 중간에 정규표현식이 사용되며 여기에 대한 자세한 설명은
http://msdn2.microsoft.com/ko-kr/library/hs600312(VS.80).aspx 을 참고하십시오.
이 글에서 사용된 예제는
http://gongdo.oranc.co.kr/Silverlight/Samples/HtmlDom/TestPage.html 에서 미리 테스트해볼 수 있습니다.
HTML DOM 참조
호스트 HTML의 DOM에 접근하는 방법Silverlight는 System.Windows.Browser 네임스페이스를 통해 호스트 HTML의 DOM에 접근하고 핸들링 할 수 있는 클래스들을 제공합니다.

매니지드 코드에서 HTML DOM에 접근하는 방법을 알아보기 전에 사용자와 상호작용이 가능한 간단한 HTML 페이지를 만들어 보겠습니다. 또한 이 예제는 Silverlight내의 매니지드 코드로 HTML DOM에 접근하는 방법을 보여주기 위한 것이므로 XAML 디자인도 간소화 하였습니다.
Howto:5-1 사용자와 상호작용하는 HTML 페이지 샘플 및 XAML 페이지 디자인
1. HtmlDom이라는 이름으로 새 Silverlight 프로젝트를 생성합니다.
2. TestPage.html의 BODY태그 안에 다음 DIV 코드 블럭을 추가합니다.
HTML
<div id="userInteraction">
<p style="font-size:20px; font-weight:bold;">매니지드 코드에서 HTML DOM 접근 예제</p>
<span style="font-size:14px">1. HTML DOM의 이벤트 핸들링</span><br />
예제 1) e-mail 유효성 검사 :
<input type="text" id="email" size="50px" /><input type="button" id="emailSubmit" value="체크" /><br />
<span style="margin-left:50px">검사 결과 : </span>
<input type="text" id="emailValidationResult" size="70" /><br /><br />
<span style="font-size:14px">2. 호스트 HTML 페이지의 속성 얻기</span><br />
예제 2) 페이지 속성 정보 :
<input type="button" id="propertiesSubmit" value="속성 가져오기" /><br />
<textarea id="properties" cols="70" rows="7"></textarea><br /><br />
<span style="font-size:14px">3. HTML DOM의 메소드 호출</span><br />
예제 3) URL 유효성 검사 및 이동 :
<input type="text" id="url" size="30" /><input type="button" id="urlSubmit" value="체크 & 이동" /><br /><br />
</div>
예제는 1. 간단한 이메일 유효성 검사, 2. HTML 페이지의 속성 얻기, 3. HTML DOM의 메소드 호출하는 방법 입니다.
3. Page.xaml의 루트 엘리먼트인 Canvas를 300 x 50 픽셀로 설정하고 TextBlock 하나를 선언합니다. 다른 HTML 엘리먼트와 구분하기 위해 배경 색상을 따로 설정하였습니다.
XAML
4. TestPage.html.js에서 호스팅할 Silverlight 컨트롤의 크기도 300 x 50으로 설정합니다.
Script
//...전략...
properties: {
width: "300",
height: "50",
//...후략...
매니지드 코드에서 HTML DOM에 접근하기 위해서 다음과 같은 코드를 사용합니다.
C#
using System.Windows.Browser;
HtmlDocument document = HtmlPage.Document;
앞서 얘기했듯이 System.Windows.Browser 네임스페이스는 자신을 호스팅하는 HTML 페이지에 접근하기 위한 다양한 클래스와 메소드를 제공합니다. 호스트 HTML 페이지는 HtmlPage 클래스로 캡슐화되고 HtmlDocument 클래스는 HTML DOM 그 자체를 캡슐화 하며 HtmlPage의 Document 프로퍼티를 통해 호스트 HTML의 HTML DOM에 대한 참조를 얻을 수 있습니다.
HTML DOM 엘리먼트의 이벤트 핸들링HtmlPage.Document 프로퍼트를 통해 얻은 HTML DOM에 대한 참조를 사용하여 HTML DOM 엘리먼트에 대한 이벤트 핸들러를 매니지드 코드로 작성한 함수로 지정할 수 있습니다. 여기에서는 앞에서 작성한 HTML 페이지의 1번 예제를 처리하는 방법을 제시합니다.
Howto:5-2 HTML DOM 엘리먼트의 이벤트 핸들링
1. Page.xaml.cs에 HTML 페이지 정보 처리와 정규 표현식 처리를 위한 네임스페이스를 추가하고 HTML DOM에 대한 참조를 클래스의 지역 변수에 저장합니다.
C#
// 다음 네임스페이스를 추가
using System.Windows.Browser;
using System.Text.RegularExpressions;
// 프로젝트의 네임스페이스 선언은 생략
public partial class Page : Canvas
{
HtmlDocument _document; // HTML DOM 참조
public void Page_Loaded(object o, EventArgs e)
{
// Required to initialize variables
InitializeComponent();
_document = HtmlPage.Document;
}
}
2. 예제 1의 버튼 클릭 이벤트를 받아서 처리할 이벤트 핸들러를 선언합니다. 내부 코드는 아래에서 추가하도록 하고 여기에서는 단지 이름만을 선언해 놓습니다.
C#
private void OnEmailClicked(object sender, HtmlEventArgs e)
{
}
3. 클래스의 생성자에 HTML DOM 참조로부터 실제로 이벤트를 부여할 엘리먼트의 참조를 얻고 이벤트 핸들러를 지정하는 코드를 추가합니다. 과정 2에서 미리 이벤트 핸들러를 선언했기 때문에 코드 입력 과정에서 인텔리센스의 도움을 받을 수 있습니다.
C#
// 예제1의 버튼 ID를 통해 이벤트 핸들러 지정
HtmlElement btnEmail = _document.GetElementByID("emailSubmit");
btnEmail.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this.OnEmailClicked));
4. 이제 실제 작동할 이벤트 핸들러 코드를 작성합니다.
C#
private void OnEmailClicked(object sender, HtmlEventArgs e)
{
// 엘리먼트의 참조 얻기
HtmlElement txtEmail = _document.GetElementByID("email");
HtmlElement txtResult = _document.GetElementByID("emailValidationResult");
// 엘리먼트의 값을 얻어와 정규 표현식으로 점검하고 결과 설정
string email = txtEmail.GetAttribute("value");
if (email == null) // 값이 설정되지 않은 경우 null이 올 수 있으므로 주의
email = "";
Regex reg = new Regex(@"\w+[@]\w+\.\w+");
if (reg.Match(email).Success)
{
txtResult.SetAttribute("value", " E-mail [" + email + "] .");
}
else
{
txtResult.SetAttribute("value", " E-mail [" + email + "] .");
}
}
5. 프로젝트를 빌드하고 F5를 눌러 테스트 해봅니다.

호스트 HTML 페이지의 속성(Property) 참조HtmlPage 클래스는 또한 현재 호스트 HTML 페이지의 유용한 속성을 제공합니다. 예제 2를 작성해 보겠습니다.
Howto:5-3 호스트 HTML 페이지의 속성 참조
1. 예제 2의 버튼 클릭 이벤트를 받아서 처리할 이벤트 핸들러를 선언합니다. 내부 코드는 아래에서 추가하도록 하고 여기에서는 단지 이름만을 선언해 놓습니다.
C#
private void OnPropertiesClicked(object sender, HtmlEventArgs e)
{
}
2. 클래스의 생성자에 HTML DOM 참조로부터 실제로 이벤트를 부여할 엘리먼트의 참조를 얻고 이벤트 핸들러를 지정하는 코드를 추가합니다.
C#
// 예제2의 버튼 ID를 통해 이벤트 핸들러 지정
HtmlElement btnProperties = _document.GetElementByID("propertiesSubmit");
btnProperties.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this.OnPropertiesClicked));
3. 이제 실제 작동할 이벤트 핸들러 코드를 작성합니다.
C#
private void OnPropertiesClicked(object sender, HtmlEventArgs e)
{
// 엘리먼트의 참조 얻기
HtmlElement txtProperties = _document.GetElementByID("properties");
// 호스트 HTML 페이지의 속성들을 표시
string output = "";
output = "절대 경로 : " + HtmlPage.DocumentUri.AbsolutePath;
output += "\n플랫폼 : " + HtmlPage.BrowserInformation.Platform;
output += "\n에이전트 : " + HtmlPage.BrowserInformation.UserAgent;
txtProperties.SetAttribute("value", output);
}
4. 프로젝트를 빌드하고 F5를 눌러 테스트 해봅니다.

호스트 HTML DOM의 메소드 호출HtmlPage 클래스는 또한 HTML DOM과 관계된 메소드를 제공합니다. 예제 3에서 지정된 URL로 이동하는 Navigate 메소드를 호출하는 예제를 작성해 보겠습니다.
Howto:5-4 호스트 HTML DOM의 메소드 호출
1. 예제 3의 버튼 클릭 이벤트를 받아서 처리할 이벤트 핸들러를 선언합니다. 내부 코드는 아래에서 추가하도록 하고 여기에서는 단지 이름만을 선언해 놓습니다.
C#
private void OnNavigateClicked(object sender, HtmlEventArgs e)
{
}
2. 클래스의 생성자에 HTML DOM 참조로부터 실제로 이벤트를 부여할 엘리먼트의 참조를 얻고 이벤트 핸들러를 지정하는 코드를 추가합니다.
C#
// 예제3의 버튼 ID를 통해 이벤트 핸들러 지정
HtmlElement btnNavigate = _document.GetElementByID("urlSubmit");
btnNavigate.AttachEvent("onclick", new EventHandler<HtmlEventArgs>(this.OnNavigateClicked));
3. 이제 실제 작동할 이벤트 핸들러 코드를 작성합니다.
C#
private void OnNavigateClicked(object sender, HtmlEventArgs e)
{
// 엘리먼트의 참조 얻기
HtmlElement txtUrl = _document.GetElementByID("url");
// 엘리먼트의 값을 가져와 정규 표현식으로 점검하고 결과 설정
string url = txtUrl.GetAttribute("value");
if (url == null)
url = "";
// 먼저 스키마 지정(http://등등)이 없으면 http://를 추가
Regex regPre = new Regex(@"([\w]+:)?//\w*");
if (!regPre.Match(url).Success)
url = "http://" + url;
// 다시 검사(RFC URL규정)
Regex reg = new Regex(@"(([\w]+:)?//)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?");
if (reg.Match(url).Success)
{
HtmlPage.Navigate(url);
}
else
{
txtUrl.SetAttribute("value", " URL.");
}
}
4. 프로젝트를 빌드하고 F5를 눌러 테스트 해봅니다.
예제 프로젝트를 첨부하였습니다.
디버깅 팁예제와 같이 어떤 개체의 참조를 문자열로부터 얻는 코드는 대단히 위험합니다. 컴파일러는 코드를 빌드하는 시점에서는 그 문자열에 사소한 오타나 문제점이 있어도 그것을 감지할 수 없기 때문에 런타임에 예외를 발생시킬 가능성이 매우 높으며 따라서 반드시 try~catch 구문을 사용하여 문제가 발생할 경우 예외 처리를 수행해야 합니다.
예를 들어 초기에 HTML 페이지에 'test'라는 ID의 엘리먼트를 배치하고 페이지를 작성하였고 매니지드 코드에서 이 엘리먼트에 디버깅 결과를 출력하였다고 합시다. 시간이 흘러 더 이상 test가 필요 없게 되었고 페이지에서 이 엘리먼트를 삭제했지만 깜빡하고 매니지드 코드에서는 관련 코드를 제거하지 않았다면 해당 코드가 실행될 때 더 이상 test라는 ID를 가진 엘리먼트를 찾을 수 없으므로 Silverlight 애플리케이션은 예외를 발생시키고 그 이후의 어떤 코드도 실행되지 않게 될 것입니다.
항상 런타임에 동적으로 바인딩 되는 개체를 참조할 때에는 반드시 예외 처리를 할 것을 강력하게 권장합니다.
참고Silverlight 공식 QuickStarts 참고:
http://silverlight.net/QuickStarts/Dom/DomAccess.aspx.NET Framework의 정규표현식 참고:
http://msdn2.microsoft.com/ko-kr/library/hs600312(VS.80).aspx정규표현식 라이브러리:
http://regexlib.com/