298 Results for 'Silverlight'

  1. 2007.06.27 WinForms On Silverlight, GOA (4)
  2. 2007.06.25 [Silverlight] 키보드 입력과 마우스 휠 이벤트 지원 (11)
  3. 2007.06.23 또 한번 경악! Silverlight for Linux, Moonlight (2)
  4. 2007.06.21 [WebAppsCon 후기] Track4. 리치 인터넷의 미래 (5)
  5. 2007.06.19 [REMIX 후기] Sivlerlight에 대한 기대감 증폭 (6)
  6. 2007.06.19 [REMIX 후기] Meet the Expert (3)
  7. 2007.06.17 웹 애플리케이션에서 가끔 실수하는 어이 없는 상황 (4)
  8. 2007.06.17 [Silverlight] 한 HTML 페이지에 여러개의 XAML페이지 로드하기 (4)
  9. 2007.06.17 [Silverlight] 스토리보드 스토리 (6)
  10. 2007.06.14 Hoons닷넷 세미나 -마법같은 애플리케이션 WPF 컨퍼런스- (4)
  11. 2007.06.14 검색의 생활화, 아직 코드에서 Name속성을 설정할 수 없네요. (5)
  12. 2007.06.14 실버라이트를 개발하다 막힐 때 검색 팁. (3)
  13. 2007.06.14 정말 알기 쉬운 실버라이트 튜토리얼 모음집 (2)
  14. 2007.06.14 경악! Silverlight 3D 프로젝트 (2)
  15. 2007.06.14 [Silverlight] 타이머 클래스 데모 (6)
  16. 2007.06.14 예술, 개발자 그리고 실버라이트 (5)
  17. 2007.06.08 실버라잇 동일 이미지 100개 로딩 실험, 제법인데? (2)
  18. 2007.06.04 [Silverlight] QuickStarts, HTML DOM의 사용
  19. 2007.05.28 [Silverlight] QuickStarts, 디버깅과 예외 처리 (3)
  20. 2007.05.28 [Silverlight] QuickStarts, 매니지드 코드의 기초
  21. 2007.05.27 [Silverlight] VISTA Glass 스타일 버튼 컨트롤 샘플 (2)
  22. 2007.05.26 [Silverlight] QuickStarts, 커스텀 컨트롤 (5)
  23. 2007.05.25 [Silverlight] Glyphs와 TextBlock의 차이점 (3)
  24. 2007.05.22 [Silverlight] QuickStarts, 이벤트 핸들링 (6)
  25. 2007.05.22 [Silverlight](수정) TextBlock의 한글 폰트 지원 문제 (3)
  26. 2007.05.19 [Silverlight] QuickStarts, 개발의 기초 (3)
  27. 2007.05.12 Visual Studio Orcas Beta1 (9)
  28. 2007.04.22 Silverlight의 가능성에 대한 생각 (2)
많은 분 들이 실버라이트에서 WinForm을 사용할 수 없느냐는 질문을 하시는데요, '아직' 불가능하다는 얘기밖에 못했어요.

그런데 NETiKA라는 회사에서 WinForms를 그대로 모사한 Silverlight 및 Flash용 라이브러리를 내놨네요. 일명 GOA WinForms.

다운받고 간단하게 만들어 봤어요.
테스트 주소 : http://gongdo.oranc.co.kr/Silverlight/Samples/GOATest/TestPage.html


보시다시피 실버라잇 위에서 구현되었음을 확인할 수 있죠.

공식 사이트의 데모 페이지 주소는 : http://community.netikatech.com/demos/

정말 대단하죠. 이런 구현을 단 1~2MB 이내에 구현하다니요.
GOA WinForms는 일반 버전과 Professional 버전이 있는데요 버전별 기능을 보면...

GOA WinForms에서 지원하는 컴포넌트
  • Control, ContainerControl, ScrollableControl, Panel
  • Button, CheckBox, RadioButton, GroupBox, Label
  • TextBox, NumericUpDown
  • ImageBox, ImageList
  • ScrollBar, HScrollBar, VScrollBar
  • Form, MessageBox, Cursor
  • ListBox, CheckedListBox
  • ComboBox
  • TreeView
  • MonthCalendar
  • TabControl, Splitter
  • ToolTip, ProgressBar, Timer
  • ToolStrip, StatusStrip, MenuStrip, ToolStripButton, ToolStripComboBox, ToolStripDropDown, ToolStripLabel, ToolStripProgressBar, ToolStripSeparator, ToolStripSplitButton, ToolStripTextBox
  • XamlCanvas (Silverlight specific)
  • GOA WinForms Professional에서 지원하는 컴포넌트

    고급 계층형 데이터그리드 컨트롤
    • 소팅- 단일/다중 컬럼 소트 기능
    • 필터링 - 통합 필터링 기능
    • Async 모드 - 주문형 행 표시
    • 고정 헤더, 행 및 컬럼 - 완벽한 컨트롤과 디스플레이
    • 사용자 정의 셀 스타일
    • 계층형 셀 - 데이터 그룹의 확장이나 축소가 가능한 계층형 셀 사용
    고급 데이터 에디터
    Date 에디터, Numeric 에디터, Mask 에디터, Color 에디터 등...
    확장 콤보박스
    확장 콤보박스 with 드랍 다운 그리드
    에러 제공자
    익스플로러 바 with 다중 뷰 스타일(VS2005 ToolBox, Outlook 2003 Navigation Pane, etc.)
    파워풀 컨트롤 스타일링
    리치 툴팁

    와~~우

    이건 뭐 기능만 보면 안되는게 없네~ 싶네요.
    그런데 예제를 만들어보니 곧바로 걸리는 게 있더라구요.

    바로 GOA WinForms의 개체들을 대상으로 애니메이션을 만들려면 Silverlight이 제공하는 Storyboard와 Timeline을 사용하여 제어할 수 없고, 전통적인 타이머 방식을 사용해야 한다는 점이에요.

    왜냐면 이들 컴포넌트들은 DependencyObject에서 파생되지 않았고 각 프로퍼티들도 DependencyProperty를 구현하고 있지 않기 때문이죠.
    DependencyObject와 Property는 몇몇 기능 구현에 있어서 매우 중요한 역할을 해요. 실제로 MS에서 제공한 실버라잇 UI 컴포넌트들은 모두 DependencyObject에서 파생되며 각 프로퍼티들은 DependencyProperty를 제공하고 있어요.

    두 번째 문제는 역시나 유니코드 지원. 하지만 이건 실버라잇도 안되고 있으니 뭐라고 할 사항은 아닌 것 같네요.

    굉장히 구현하는데 시간이 많이 걸렸을 것 같은데, 사실 이 부분... MS가 마음만 먹으면 WinForms와 거의 완벽하게 같은 환경을 구현하는건 일도 아니잖아요?
    뭐, 그러길 바라구요.

    하여간 대단한 라이브러리네요.

    Posted by gongdo
    키보드 입력과 마우스 휠 이벤트 지원

    현재 실버라이트는 아직은 베타 상태이기도 해서 갖가지 버그도 있고 언어적 지원이 부실한 곳도 있어요. 하지만 언제나 그렇듯 아키텍처 자체에서 불가능한 일이 아니라면 어느 정도 핵hack과 트릭trick이 있게 마련이죠.

    사용자 입력 인터페이스의 관점에서 제일 아쉬웠던 건 마우스 이벤트를 이동과 왼쪽 버튼에 한정시킨데다가 플래쉬 최대의 문제점인 오른쪽 버튼 클릭시 강제로 플래쉬 메뉴가 뜨는 것과 같이 덜렁 Silverlight 링크 메뉴 하나 던져준다는 점이었죠.

    그 외에도 마우스 휠 이벤트가 아예 고려되어 있지 않고 키보드 입력 지원도 몇몇 키의 지원이 버그로 지원되지 않는 점이 있어요. 특히 방향키의 Down 이벤트가 발생하지 않는 버그는 좀 황당하네요.

    이런 기본적인 문제점 들은 아마도 정식 버전이 나오면서 한방에 해결될 가능성이 높지만, 지금 당장 써먹을 필요가 있다면 핵을 쓰는 수밖에요.

    Scriptable 지원

    이런 문제점들의 해결은 의외로 간단한 편이에요. 실버라잇 컨트롤은 HTML 페이지에 호스팅 되며 사실 실버라잇에서 지원해주는 사용자 입력 이벤트는 HTML 페이지에서 발생되는 이벤트를 핸들링하여 전달해주는 것 뿐이죠.

    따라서 HTML 페이지에서 실버라잇 컨트롤에 발생하는 이벤트를 Javascript로 핸들링하여 다시 실버라잇 컨트롤로 던져주는 코드를 작성한다면? 충분히 가능해 보이죠?

    그런데 이것을 구현하려면 Javascript와 매니지드 코드와의 연동이 필요해요. 하지만 어떻게?

    바로 이러한 종류의 연동을 위해 실버라잇은 Scriptable이라는 방법을 제공하고 있어요.

    원래 이 주제는 QuickStarts의 일부로 다룰 예정이었는데 당분간 QuickStarts는 쉬고 있어서 아직 포스팅을 못했어요. 이 부분을 공부해보실 분은 http://silverlight.net/QuickStarts/Dom/ManagedCodeAccess.aspx 이곳을 참고하세요.

    간략하게 소개하자면, 코드-비하인드에서 [Scriptable]이란 어트리뷰트를 부여한 public 클래스와 메소드 및 프로퍼티를 애플리케이션 전역의 Scriptable 개체로 등록하고 이것을 Javascript에서 접근할 수 있게 하는 방법이에요. 실버라잇 컨트롤에서 키를 눌렀을 때(KeyDown) 처리를 수행하는 간단한 샘플 코드를 작성해보자면 다음과 같아요.

    Scriptable 샘플(KeyDown 이벤트 처리)
    1. 코드-비하인드에 [Scriptable] 개체를 작성합니다. (기본적인 Using 구문 생략)
    C#
    using System.Windows.Browser; // 호스트 브라우저 클래스 지원

    [Scriptable]
    public class ScriptableSample
    {
        [Scriptable]
        public void FireKeyDown(int keyCode)
        {
            // Down된 keyCode를 처리...
        }
    }

    2. 코드-비하인드에서 작성된 Scriptable 개체의 인스턴스를 생성하고 애플리케이션에 등록합니다. 이 작업은 일반적으로 페이지의 메인 코드에서 수행됩니다.
    C#
    using System.Windows.Browser; // 호스트 브라우저 클래스 지원

    public class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();

            ScriptableSample scriptable = new ScriptableSample();    // 생성
            WebApplication.Current.RegisterScriptableObject("ScriptableKey", scriptable);    // 등록
        }
    }

    3. Javascript로 Scriptable로 등록된 실버라잇 컨트롤의 개체를 획득하고 실버라잇 컨트롤에서 발생하는 이벤트를 핸들링하는 코드를 작성.
    Javascript
    var silverlightControl = null;
    var scriptableObject = null;

    // 실버라잇 컨트롤과 Scriptable 개체를 획득
    // elementName - 실버라잇 컨트롤을 호스팅하는 엘리먼트의 이름
    function LoadScriptable(elementName)
    {
        // 실버라잇 컨트롤 바인딩
        silverlightControl = document.getElementById(elementName);

        // KeyDown 이벤트 핸들러 등록
        silverlightControl.onkeydown = HandleKeyDown;

        // 실버라잇 Scriptable 개체 지정, Key는 반드시 매니지드 코드에서 설정한 값을 사용할 것.
        // (setTimeout으로 딜레이를 줘야함)
        var scriptableKey = 'ScriptableKey';
        var scriptableObjectBinding = 'scriptableObject = silverlightControl.Content.' + scriptableKey;
        setTimeout('eval(scriptableObjectBinding);', 1);
    }

    // KeyDown 이벤트 핸들러
    function HandleKeyDown(event)
    {
        if (!event) // IE
            event = window.event;
       
        var
    keyNum = 0;
        if(window.event) // IE
            keyNum = event.keyCode;
        else if(event.which) // Netscape/Firefox/Opera
            keyNum = event.which;

        if ( scriptableObject != null )
            scriptableObject.FireKeyDown(keyNum);
    }

    // Scriptable 개체를 로드
    LoadScriptable('SilverlightControl');


    여하튼, Scriptable을 사용하려면 최소한 HTML 페이지의 이벤트를 핸들링 할 추가적인 Javascript 코드, Scriptable 개체 및 Scriptable 메소드(또는 프로퍼티)를 선언하고 이것을 WebApplication에 등록해야 하는 상당히 귀찮은 작업을 반복해야 하죠.

    게다가 Scriptable이 필요한 HTML 페이지 마다 저런 Javascript 코드를 Copy&Paste 한다는 건 너무 너무 너무 너무 너무나도 소모적이고 비효율적인 작업이 될 거에요.

    단지 깔끔한 매니지드 코드로 작성된 클래스 하나로 이런 기능들을 한방에 지원할 수 없을까... 고민해보고 답을 얻었습니다.

    HTML DOM에 동적으로 Javascript 추가

    QuickStarts, HTML DOM의 사용에서 매니지드 코드에서 HTML DOM에 접근하고 제어하는 방법에 대해 소개했었죠. HTML DOM은 W3C에서 표준으로 제정되었기 때문에 어떤 언어라도 같은 기능을 가지고 있음을 확신할 수 있는데요, HTML DOM의 메소드 중에는 DOM에 태그 이름을 통해 새 엘리먼트를 동적으로 추가할 수 있는 AppendChild라는게 있어요.

    그럼, Javascript 구문을 <script>태그로 추가하고 이 태그의 Text 내용을 위의 샘플에서 귀찮게 작성한 코드로 설정한다면? 앉아서, 아니 누워서 마음대로 Javascript를 추가하고 제어할 수 있겠죠?

    동적으로 Javascript를 추가하는 아주 간단한 예를 들어 보자면...
    C#
    using System.Windows.Browser; // 호스트 브라우저 클래스 지원

    public class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();

            // HTML DOM에 Element 추가하기
            HtmlDocument doc = HtmlPage.Document;
            HtmlElement ele = doc.CreateElement("script");
            ele.SetProperty("Text", @"alert('매니지드 코드에서 작성한 스크립트!');");
            doc.DocumentElement.AppendChild(ele);
        }
    }

    간단하죠?

    이 트릭을 이용하면 대부분의 Javascript를 매니지드 코드에서 동적으로 생성하여 붙여 넣을 수 있는 엄청난 가능성이 생겨요.

    이번 포스팅에서는 샘플들의 프로젝트를 첨부하지 않았고 대신, 실제로 써먹을 만한 완성된 프로젝트를 첨부했으니 코드를 보고 연구해보시길 바래요. Scriptable은 약간은 복잡하고 어려운 부분이니까 강좌 형식으로 쓰고 싶었는데 지금은 그렇게 하기가 무리가 있네요. :(

    프로젝트는 키보드 입력(KeyDown, KeyPress, KeyUp) 및 마우스 휠 이벤트 정보를 출력하는 테스트 페이지에요.

    프로젝트 테스트 :
    http://gongdo.oranc.co.kr/Silverlight/Samples/ScriptableTester/TestPage.html

    ScriptableTester.zip

    스크립터블 프로젝트



    Posted by gongdo
    아... 역시 고수의 세계는 한없이 멀리 있네요.

    실버라잇 페이지를 리눅스 상에서 볼 수 있게 해주는 실버라이트 플러그인 프로젝트가 Moonlight 라는 이름으로 공개되었네요.

    자세히 안봤지만 아마 리눅스에서 닷넷 플랫폼을 구현하는 MONO 프로젝트의 서브 프로젝트가 아닌가 싶은데, 여하튼 사이트를 소개합니다.


    (리눅스 상의 불여우에서 구동한 Silverlight Airline 데모)

    문라잇 스샷 페이지 :
    http://www.mono-project.com/MoonlightShots

    문라잇 공식 페이지 :
    http://www.mono-project.com/Moonlight

    이 작업에 하루에 12~16시간씩 21일이 걸렸다는 군요.
    대단하단 말 말고 뭐라 할 말이 없습니다.
    Posted by gongdo
    비도 시원~하게 내리는 오늘, 웹앱스콘에 다녀왔습니다.
    원래 비전 나잇까지 가서 뭔가 사람도 좀 만나보고 싶었는데, 저에겐 다행하게도 MS의 황리건님과 김국현님과 잠깐이나마 인사하고 대화를 할 수 있어서 다른건 가볍게 포기하고 집에왔네요. 스프링노트는 관심있었는데 그것까지 듣고 올걸 하는 후회도 쬐끔...

    방금전까지 담소(?)를 나누다 온 황리건님께는 연이어 아픈 얘기지만 실버라잇이 준비가 제일 부족해보였어요 ㅠ.ㅜ 물론 오늘 발표된 기술들 중에서 베타 심지어 알파딱지도 아직 떼지 못한 것이기도 하지만요.

    실버라잇에 집중하고 있으니 좀 더 자세히 얘기해보자면 실버라잇이 관심을 못받는 가장 큰 이유는 아마도 디자이너의 저변 부족이 아닐까 생각해봅니다. 두번째 세션인 쇼핑몰 예에서도 아주 적절하게 짚어 주셨듯이 Rich한 사용자 인터페이스는 XHR도 벡터 그래픽도 프로그래머빌리티도 아닌 단지 버튼아래 적절한 그림자 표현이 더 크게 다가온다는 점이에요.

    무슨 얘기냐면 제 아무리 훌륭하고 멋드러진 기능으로 무장하더라도 디자인 감각 없는 개발자가 그걸 활용해봤자 일반 사용자에겐 아무런 감성도 전달할 수 없다는 것이고 RIA의 구현에서 가장 핵심적인 것은 아주 기초적인 디자인, 나아가 사용자가 쉽게 접근할 수 있는 인터페이스가 아닐까요?

    다음으로 개발적인 측면에서 아직 공식 버전이 런칭되지 않았기 때문이겠죠. 프로덕션을 위한 런타임에 'Beta' 'Alpha'가 뜨는건 일반 유저에게 썩 기분좋은 일이 아닐거에요. 이것만으로도 큰 감점요인이죠. 물론 1.0 Beta는 올여름 느즈막히 공식 버전으로 런칭한다고 하지만, 1.1 Alpha는 연말로 미뤄진 것 같네요. 사실 개발자로써 1.0 Beta, JavaScript버전은 별 활용가치가 없다고 생각해요. 실버라잇의 진짜 위력은 1.1 Alpha, CLR 버전에 있고 실제 실버라잇 코드 작성에 있어서 JavaScript 개발 환경이 CLR 혹은 DLR 개발환경보다 우위에 있는 점이라곤 눈꼽만큼도 없다고 장담할 수 있어요. 이 얘긴 나중에 따로 하기로 하죠.

    다음 세션으로 쇼핑몰 구축 사례인데요, 집에 와서 좀 둘러봤지만 사이트 자체는 썩 마음에 들진 않지만 개발 사례와 경험 그리고 사이트 구축에 대한 식견은 만점을 줄 수 있어요.

    사이트 자체에 높은 평가를 못내리는 가장 큰 이유는! 일단 접속하자마자 반겨주는 '오류가 있습니다. 디버그 하시겠습니까?' 메시지. 아마 어도비 쪽 기술을 사용하는 웹 개발자들은 비주얼 스튜디오를 사용하지 않으시겠지만 비주얼 스튜디오 사용자들은 자바스크립 오류가 있는 사이트를 무지 싫어해요. 편집증 말기의 과민성 환자인 디버거가 사소한 오류에도 반응하거든요. 실수로라도 '예'를 눌렀다간 한참동안 디버거 띄우고 취소하고 어쩌고 짜증이 밀려오죠.

    뭐 그래봤자 이런 개발자는 애초에 고객으로도 무시당할 만한 한국 최악의 계층이니까 상관 없겠지만(하아... 이런 말에 일일이 농담이에요~^^* 이렇게 쓰지 않아도 되면 좋겠습니다) 제 취향에도 좀 안맞는거라 별로 좋아보이지가 않았어요. 그래봤자 이것도 '개편후 매출이 늘었습니다!'란 한마디에 그냥 제 취향이 이상한게 되는거죠.

    이게 중요한게 아니고 쇼핑몰 사례의 핵심은 RIA RIA 입으로만 떠들어봤자 고객들에겐 아무런 영향이 없고, 기존사이트와 99.9% 똑같은 구성을 하더라도 버튼 하나, 장면 전환 하나하나에 새로운 기술들을 도입해 나가는게 보다 고객에게 어필할 수 있다는 점이죠.

    그런 자연스러운 기술 전환에 대해서는 좋은 평가를 받을만 한 것 같아요.


    마지막 세션인 Raju Bitter씨의 OpenLaszlo는 정말 정말 정말 정말 정말 정말 정말 x 100 훌륭했어요.
    아니 여태 이런걸 모르고 있었지? 란 생각이 머리속을 가득 채우네요.
    사실 AJAX도 기술적인 관점에서는 그야말로 역사에 남을 뒷북이었는데 OpenLaszlo를 여태 몰랐다는게 엄청나게 부끄러워요. 아 어디가서 RIA니 웹 2.0이니 안다고 나불거리지 말아야지;;;

    우선 링크부터 갑니다.
    http://www.openlaszlo.org/

    RIA, WEB 2.0 이딴거 다 집어치우고 웹쪽에 관심있다고 하시는 분은 무조건 들어가서 20분만 둘러보세요. 아 이래서 영어를 잘해야 하는데... ㅠ.ㅜ

    그 중에서도 제가 얘기하고 싶은, 또 지향하는 핵심 구현 사례는 바로 이것.
    http://www.click-shirt.com/

    진짜 사용자 친화적인, 쉬운, 직관적인, 그러면서도 Rich한 UX가 무엇인가를 단 세페이지로 '구현'하고 있습니다.

    Raju씨도 중간에 언급했지만 컴퓨터에 대한 지식이 없는 사용자들은 화면 전환이 일어나면 쉽게 내비게이팅을 하지 못한다는 점, 화면에 어떤게 메뉴고 어떤게 무슨일을 하는지 파악하는데 시간이 많이 걸린 다는 점을 잘 고려해야 합니다.

    언제까지나 '국내 정서에는 안맞다' 라고 틀에 박힌 포털식 사이트만 만드는게 능사가 아니란거에요. 또 앞으로 다가올 IPTV시대, 즉 리모콘으로 조작하는 웹에 대한 비전도 좀 더 현실적으로 다가오고 있구요.

    물론 이 데모는 단지 티셔츠라는 단순한 컨텐트만을 표현하는 게 전부지만, 초기 화면은 포털식 구성을 하더라도 개별 상품 카테고리 내에서는 이런 식의 직관적인 인터페이스로 구현하는게 어떨까 생각해봅니다.

    제가 잘 이해하고 있는건지 확신이 안가지만, OpenLaszlo는 XML기반의 마크업과 ECMAScript(Javascript의 기초 언어) 문법으로 작성되어 이것을 컴파일하면 옵션에 따라 Flash 7, 8, 9 또는 DHTML로 결과물이 빌드되는 아키텍쳐를 가지고 있어요.

    OpenLaszlo의 사용 편의성이나 개발자 지원, 도큐멘팅 이런걸 떠나서 이러한 중간언어적인 시도는 웹 표준화에 크게 기여하면서도 동시에 개발 플랫폼의 다양성도 양립할 수 있는 가능성을 보여준다는 점에 가장 높은 점수를 주고 싶어요.

    이와 관련해서, .NET Framework는 애초에 개발 랭귀지에 관계없이 중간 언어로 컴파일한 뒤 .NET 런타임하에서 평등하게 실행되는 개념인데 바로 이런 개념과도 유사하다고 볼 수 있겠죠.

    다시 실버라잇으로 돌아와서, 제가 Silverlight 1.1 alpha를 보고 턱 빠지게 놀랐던 건 CLR환경 뿐만 아니라 DLR이라는 이름으로 다른 언어들까지도 지원을 할 수 있는 가능성을 열어둔 점이었어요. 대표적으로 JScript, 파이썬.

    실버라잇 1.1이 애초에 이러한 멀티 랭귀지 환경을 고려하고 있는 만큼 경우에 따라선 OpenLaszlo의 컴파일 결과물이 Silverlight이 될 수도 있겠고 반대로 Silverlight에서 OpenLaszlo의 문법을 수용하는 중간 언어가 만들어 질 가능성도 있다는 거죠. 물론 이런 가능성은 정치적인 이유로 성사되지 않을 가능성도 농후하지만요.

    과장해서 말하자면, 프로그래밍 랭귀지간 매쉬업까지도 생각해 볼 수 있다는 거에요!

    OpenLaszlo는 그 역사에 비해 오랫동안 몰랐다가 처음 접한 것도 있고 해서 약간은 흥분 상태에서 포스팅을 해서 오바가 심하긴 하지만, 웹의 미래에 대해 상당히 의미있는 생각들을 제게 던져준 것 같아요.

    포스팅이 길어진데다가 컨퍼런스 내용과 겹쳐서 다음 글에 계속...
    Posted by gongdo
    이번 REMIX 행사를 한 단어로 표현하자면 Silverlight 일거에요.
    그만큼 데모와 발표 내용과 관심의 초점은 실버라잇에 맞춰있었단 거죠.

    브라이언씨의 첫 키노트를 힐끔 보고는 MIX'07의 재탕(Re)인 것 같아서 보다 빠져나와서 박경훈님이랑 김영욱님과 잡담이나 나누고 다음 세션은 별로 기대 안하고 있었는데 이게 웬걸, 어디서 이런 업체들과 사이트들이 준비를 하고 있었는지 상당히 수준급의 데모들이 나오더군요.

    그간 실버라잇에 관한 포스팅을 하면서 스스로 만족하고 있었는데 심하게 위축되네요. 7월 7일 발표 준비중인 세미나도 밑천이 다 드러난 것 같아서 조금은 의기소침해졌다랄까...

    아니 정말로 그간 실버라잇을 다루면서 생각해 왔던 것들이 이미다 구현되어가고 있고 특히 모션클라우드의 Silverlight을 사용한 블로깅은 내가 생각하던 것 그 자체 아닌가! 치사하다 모션클라우드!!

    네, 세상은 혼자만 생각하고 혼자서 개발 해서는 아무것도 안되게 돌아가는 것 같네요. 여하튼.

    SBS의 새로운 방송 기획, IPTV를 염두한 Sivlerlight로의 데모는 기획하는데 1주일 만드는데 1주일 걸렸다네요.

    허...참... 전 허접한 포토 갤러리 만드는데 2주 동안 뭉기적 거리고 있는데 말이에요 ㅠ.ㅜ 그쪽 개발사(당연히 개발은 다른 곳에서 했죠)의 명함을 얻어왔으니 연락해서 굽신거려볼까...

    발표에 참여했던 NHN과 DAUM... 비교가 안될 수 없더군요. 정말이지 NHN, 네이버는 이제는 뒤집기가 불가능해진 안드로메다까지 간건가... 좀 민감한 얘기이고 제가 이야기의 근거가 될만한 근거는 없어서 그만둘께요.

    뭐 화려한 데모도 좋았지만 그보다도 고무적인 건 바로 실버라잇의 성능 관련 문제에요.

    대체로 RIA를 표방하는 기술들이 웹에서 돌리기엔 무겁다, 느리다, 성능이 안나온다... 이런 얘기를 많이 듣잖아요? 그런 점에서 실버라잇은 겨우 알파, 베타 버전이면서도 성능은 확실히 좋다. 라고 자신있는 얘기가 나온다는 게 실버라잇에 올인 중인 저에겐 참 고무적인 일이죠.

    NHN 세션에서 한게임의 Silverlight 게임 데모를 통해 그런 얘기가 나왔는데요, 아직 자체 컨트롤이나 기능 지원 특히 한글 지원이 미흡해서 그렇지 프레임웍의 성능 자체는 괜찮다라고 하네요. 뭐 컨퍼런스에 나와서 이거 안좋아서 못써먹겠다 이런 얘기는 안하겠지만 적어도 데모의 구동 상태를 보면 믿어도 좋을 것 같았어요.

    마지막으로 연극...을 가장한 한국 마소 직원들의 눈물나는 데모쇼.
    ...아 참 뭐라 할 말이 없네요.
    어쨌든 데모 준비는 좀 잘 해오시지...

    데모에서 발생한 문제점은 혹시나 보신 분들을 위해 얘기드리자면 절대로 네임스페이스 지정이나 어셈블리 참조 등의 문제는 아닙니다. 실버라잇 1.1의 최대 장점이 뭔데요, 바로 CLR 환경에의 통합이잖아요. 그런 문제는 애초에 빌드 타임에 컴파일 에러로 나올테니 그런 문제는 아니고 뭔가 개체의 이름을 잘못 지정했거나 했겠지요. 문법이나 레퍼런스 등의 문제는 아니었다구요!

    전체적으로 웹 개발자들에게 자극이 되는 좋은 행사였다고 생각해요.
    특히 국내 환경에 맞게 지역화된 데모들은 참 좋았구요. 의기소침해지기도 했지만 다시 의욕을 넣을 만한 것이기도 했고... 힘내야죠.

    이번 행사를 통해 많은 개발자들이 실버라잇에 관심을 가지고 서로 교류할 수 있는 계기가 되었으면 합니다. 옆동네 Apolo/Flex 카페랑 Silverlight 카페랑 비교해보면 정말 눈물나거든요.


    한줄 요약 : 님하 Silverlight에 관심점... 굽신굽신.
    Posted by gongdo
    WPF를 열심히 하다가 돌연 실버라잇으로 선회한 것은 MIX'07의 키노트와 몇몇 발표를 보고 나서에요. 아마 오늘 REMIX의 발표를 보신 분 들중에도 실버라잇으로 급선회 하는 분들이 많아 질거란 생각이 들어요.

    행사 시작전에 조촐한 unconference에서 브라이언 골드팝씨랑 로렌스 모로니(이분 발음 무지 어렵습니다)씨와의 질답시간이 있었고 김영욱님의 간단한 실버라잇 소개가 있었는데 행사 전체적으로 이런 시간이 좀 더 많았으면 좋았을걸...이란 생각이 드네요. 특히 김영욱님은 시간에 쫒겨서 데모도 제대로 할 수 없었거든요. (10분가지고 무슨 얘길 하겠습니까;; )

    여하튼, 질문하면 무조건 책준다길래 냅따 첫질문을 날렸고 뭐 예상대로의 '정판 나올때까지 기둘려라'라는 답변을 얻었네요. 덤으로 얻은 책은 ASP.NET AJAX. 그렇지 않아도 AJAX책 하나 필요했는데 잘됐죠. 히히힛. 오고간 질문들을 정리해보자면...

    Q1. Silverlight에서 지원하는 IsolatedStoreage가 현재는 Per Application 단위로 작동해서 한사이트에서 데이터를 공유하기 어렵다, Per Domain이든 Per Site든 지원 범위를 늘릴 계획은 없나?

    A1. 아직 Silverlight은 Application의 관점에서 진행중이고 보다 넓은 범위의 지원은 개발자들의 Feedback을 적극 수용할 '예정'이다. 아마도 그러한 지원은 Silverlight 1.1의 다음 버전에서 가능할 것이라고 생각한다. Feedback 많이 날리시라.

    Q2. Silverlight의 공식 발표는 언제?

    A2. 1.0은 올 여름 느즈막히 할 예정이고 1.1은 올 연말로 예정되어 있다.

    Q3. Silverlight의 소켓 지원 여부는?

    A3. 우리들도 Silverlight에서의 소켓 프로그래밍에 관심이 많지만, 현재까진 지원되지 않고 있으며 다만, ASP.NET이든 PHP든 웹 서버와의 적절한 통신을 통해 서버사이드에서 소켓 지원을 얻을 수 있을 것이다. Silverlight 1.1의 다음 버전에서는 지원될 수 있도록 노력하고 있다.

    Q4. Sivlerlight VS Flex에 대한 생각을 말해달라.

    A4. ...하나 마나한 소리라 자체 편집. 이딴 내용은 그냥 Silverlight, 실버라이트로만 검색해도 수두룩 합니다. 전 기껏 힘들게 마련한 미팅에서 이따위 질문을 날리는 사람을 이해할 수가 없어요.

    Q5. Windows 2003서버와 롱혼(2008) 서버에서의 스트리밍에 대해...

    A5. (이 부분은 직접적인 관심사가 아니라 제대로 안들었네요.) Windows 2k8 서버에서는 IIS7이라는 환경에 웹, 미디어, 스트리밍 등 모든 서버 요소가 통합될 것이고 특히 Silverlight은 다운로드 가능한 WMV 포맷, 스트리밍을 위한 MMS 포맷을 지원할 것이며 고화질 HD 표현이 가능한 VC-1 코덱의 포맷도 사용 가능할 것이다. Silverlight를 프론트 엔드로 내세운다면 더불어 크로스 플랫폼으로써의 이점도 얻을 수 있다.


    참 물어보고 싶은게 산더미 같았지만 이 두 사람은 키노트 발표 예정도 되어있고 애초에 일정도 빡빡(겨우 20분)해서 삼킬 수밖에 없었네요.

    나중에 행사장에 온 박경훈님하고도 얘기했지만, Silverlight.net이나 MSDN 포럼 등을 보면 MS 본사의 실무자들도 답변을 남겨주는 걸 보면 무지 부러운데 한국 MS는 아직 그럴 인력도 여력도 없어 보여서 많이 아쉬워요.

    새로운 기술에 대해서는 본사의 직접적인 기술 지원이 무엇보다도 도움이 될텐데 말이에요. 쩝쩝.

    두 Expert들을 만나보고는 겨우 10분 남은 시간동안 김영욱님께서 뭔가 데모를 준비하셨는데 주변 환경도 그렇고 시간도 그렇고 뭐하나 제대로 할 수 있는 상황이 아니었어요. 그냥 그렇게 흐지부지...

    전체적으로 많이 아쉽네요. 좋은 프로그램이 될 수 있는 것을 말도 안되는 시간으로 잡아 놓은 것도 그렇고, 주변 환경 통제도 적절치 않았던 것 같아요.

    ...그래도 저자의 사인이 들어간 책 한권은 얻었으니 저는 대만족 히힛.
    Posted by gongdo
    http://blog.naver.com/super810910/60038851235 에서 트랙백.
    실버라잇에서 대사건 발생!!






    갑자기 누구냐!!! 넌;;;;

    삽질 결과물.
        <div id="nakhoon1" >
            <script type="text/javascript">
                createSilverlight("nakhoon1", "300", "200", "Page.xaml", "super1");
            </script>
        </div>
       
        <div id="nakhoon2" >
            <script type="text/javascript">
                createSilverlight("nakhoon2", "100", "100", "Page1.xaml", "super2");
            </script>
        </div>

    뭐야 하나도 안고쳤잖아! 뭐가 문제야?!

    ...딱 하나 있죠.

    그건...




    그건....





    그건.......









    "page"가 아니고 "Page"란 사실!!!




    네, 문제의 원인은 다른 무엇도 아니라 oranc 계정에 있었어요.
    oranc 계정은 URL request의 대소문자조차 구분하는 깐깐함을 보이는데요, 당연히 윈도 로컬 시스템상에선 대소문자 구분이 없으니 잘 되지만 기숙사 B 사감 같은 오란씨 계정에선 파일을 못찾았겠죠. -ㅅ-

    이런 일은 특히 유닉/리눅스 계열에서 많이 발생하고요... 제 생각에 URL마저 대소문자를 구분할 필요는 없을 것 같은데 말이에요. 쩝.

    어쨌든 아래는 테스트 해본 것.
    http://gongdo.oranc.co.kr/Silverlight/Samples/Nakhoon/TestPage.html

    Posted by gongdo
    낙훈님의 멋진 포스팅, [silverlight유치원졸업작]합체와 다중에서의 트랙백.

    기본 실버라이트 프로젝트에서 TestPage.html.js에서 createSilverlight() 메서드는 정해진 실버라이트 페이지를 고정된 HTML 엘리먼트 위에 올리는 역할을 하죠.

    낙훈님의 테스트에서 한 페이지에 여러개의 실버라잇 페이지를 올리도록 이 메서드를 수정하셨는데 한가지 놓치신 게 있더라구요.

    뭐 간단히 말해서 다음의 함수를 사용하시면 돼요.

    function createSilverlight(xamlPage, parentID, controlID, panelWidth, panelHeight)
    {
     Sys.Silverlight.createObjectEx({
      source: xamlPage,
      parentElement: document.getElementById(parentID),
      id: controlID,
      properties: {
       width: panelWidth,
       height: panelHeight,
       version: "0.95",
       enableHtmlAccess: true
      },
      events: {}
     });
    }

    그리고 HTML 코드는 다음과 같이...

        <div id="Parent1" >
            <script type="text/javascript">
                createSilverlight("Page.xaml", "Parent1", "Page1", "100", "100");
            </script>
        </div>
        <div id="Parent2" >
            <script type="text/javascript">
                createSilverlight("Page1.xaml", "Parent2", "Page2", "100", "100");
            </script>
        </div>

    여기서 중요한 건,
    Sys.Silverlight.createObjectEx 메서드를 호출할 때 parentElement와 id 속성이 중복되면 안된다는 점이에요. 낙훈님의 예제에서는 id 속성이 같은 값을 가졌기 때문에 안됐던 걸로 보이네요.

    어쨌든, 단순히 빨간 배경, 검정 배경을 가진 두 Page를 올린 예제 프로젝트를 첨부했으니 확인해보세요.
    LoadMultipleSilverlightObject.zip

    여러 XAML 페이지 로드하기


    동작 데모는 아래에서...
    http://gongdo.oranc.co.kr/Silverlight/Samples/LoadMultipleSilverlightObject/TestPage.html

    보시다시피 웹서버상에서도 잘 되...죠? (설마...)
    Posted by gongdo
    Storyboard XAML 문법의 난해함

    UI 프로그래밍 기법에 있어서 WPF와 Silverlight의 가장 큰 특징은 Storyboard와 Animation 개체를 사용한 애니메이션의 구현이 아닐까 생각해요. 물론 비슷한 개념은 이미 플래쉬나 다른 곳에서도 볼 수 있었지만요.

    그런데 이 스토리보드와 애니메이션을 수작업으로 XAML 코딩 한다는 건 만만치가 않습니다. 바로 애니메이션의 대상 개체와 대상 속성을 지정하는 문법의 귀찮음난해함 때문이죠.

    간단하게 테스트 해볼까요?
    페이지가 로드 되었을 때 다음과 같은 Rectangle 엘리먼트가 오른쪽으로 100픽셀 이동하면서 회전하는 애니메이션을 Expression Blend를 사용하지 않고 코딩해보세요. 단, Orcas를 사용해도 좋습니다.

    <Rectangle Width="100" Height="100" Canvas.Left="50" Canvas.Top="100" Fill="Black" />

    이걸 고민 없이 해내는 분이 있다면 쓰부로 모실테니 연락주세요!

    당연한 얘기지만 전 그렇게 못해요. 그래서 이런 애니메이션을 만들 땐 곧바로 Expression Blend로 프로젝트를 열어보지요.
    블렌드로 대충 끄적여 볼까요? 간단한 과정인데 캡쳐하기가 애매해서 동영상으로 캡쳐했어요.


    원본은 800 x 600이니까 다운 받아서 보세요.
    http://gongdo.tistory.com/attachment/cfile5.uf@25123E3A5878F5810E67EB.wmv


    대략 아래와 같은 XAML 코드가 만들어질거에요. (루트 엘리먼트는 생략.)
    XAML
    <Canvas.Triggers>
        <EventTrigger RoutedEvent="Canvas.Loaded">
            <BeginStoryboard>
                <Storyboard x:Name="Timeline1">
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                        <SplineDoubleKeyFrame KeyTime="00:00:01" Value="100"/>
                    </DoubleAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="rectangle" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)">
                        <SplineDoubleKeyFrame KeyTime="00:00:01" Value="360"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Canvas.Triggers>

    <Rectangle Width="100" Height="100" Canvas.Left="50" Canvas.Top="100" Fill="Black" RenderTransformOrigin="0.5,0.5" x:Name="rectangle" >
        <Rectangle.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="1" ScaleY="1"/>
                <SkewTransform AngleX="0" AngleY="0"/>
                <RotateTransform Angle="0"/>
                <TranslateTransform X="0" Y="0"/>
            </TransformGroup>
        </Rectangle.RenderTransform>
    </Rectangle>

    와... 이거 코딩은 고사하고 해독하는데도 만만치가 않네요. 단지 몇 픽셀 옮기면서 돌렸을 뿐인데...
    특히 이 코드의 백미는 Storyboard.TargetProperty의 복잡함이죠. 죄다 문자열이라서 인텔리센스의 도움을 받을 수 없는데 베이스 클래스의 이름부터 순서대로 쫘악 나열해야 하는데 중간에 배열 번호까지 들어가요. 해당 속성이 컬렉션일 경우엔 추가된 순서까지 맞춰서 코딩해야 한다는 거죠.

    이쯤되면 수작업으로 작성하는 건 GG죠.

    이런 이유로 실버라잇의 애니메이션은 그냥 블렌드를 사용하여 작성하는게 정신 건강에 훨씬 좋아요. 블렌드에서 대충 원하는 형태의 애니메이션을 만들고 세부적인 값을 수정하는 거죠.

    현재 스토리보드의 문제점

    그나마도 디자인타임에 애니메이션이 고정되는 건 블렌드와 약간의 수정을 통해 뭐라도 만들 수 있어요. 하지만 동적으로 순간순간 변화하는 변수를 적용해야 하는 애니메이션이 있다면? 그럼 더 머리 아파지죠.

    여기에서 XAML과 코드-비하인드를 연계하여 코딩하는데 익숙하신 분이라면 XAML의 Canvas나 TransformGroup 엘리먼트처럼 하위 엘리먼트를 포함할 수 있는 경우 코드-비하인드에서는 object.Children 이라는 컬렉션 속성을 통해 하위 엘리먼트에 접근하거나 추가/삭제 할 수 있다는 걸 아실거에요. 예를 들어 위에서 작성한 XAML을 개체 트리로 나타내 보자면 다음과 같습니다.


    이것을 다시 의사 코드로 작성해보면 아마도 아래와 같겠죠
    C# (의사 코드)
    Canvas canvas = new Canvas();    // 새 캔버스 생성

    BeginStoryboard bs = new BeginStoryboard();    // 새 스토리보드 시작기 생성

    Storyboard sb = new Storyboard();    // 새 스토리보드 생성

    DoubleAnimationUsingKeyFrames dak = new DoubleAnimationUsingKeyFrames();    // 더블 애니메이션 생성
    dak.KeyFrames.Add( new SplineDoubleKeyFrame() );    // 애니메이션에 키프레임 추가

    sb.Children.Add( dak );    // 스토리보드에 생성한 애니메이션 추가

    dak = new DoubleAnimationUsingKeyFrames();    // 다른 애니메이션 새로 추가
    dak.KeyFrames.Add( new SplineDoubleKeyFrames() );

    sb.Children.Add( dak );

    bs.Storyboard = sb;    // 스토리보드를 설정

    Rectangle rect = new Rectangle();    // 새 사각형 생성

    TransformGroup tg = new TransformGroup();    // 새 변형 그룹 생성

    tg.Children.Add( new ScaleTransform() );        // 변형 그룹에 변형 규칙 추가
    tg.Children.Add( new SkewTransform() );
    tg.Children.Add( new RotateTransform() );
    tg.Children.Add( new TranslateTransform() );

    rect.RenderTransform = tg;    // 사각형의 변형 속성을 설정

    canvas.Children.Add( tg );    // 사각형을 캔버스에 추가

    canvas.Triggers.Add( bs );    // 스토리보드 시작기를 캔버스의 트리거에 추가

    꽤나 복잡해 보이지만 위의 개체 트리 구조를 보면 별로 어려울 건 없을 거에요. XAML에서 하위 요소는 코드-비하인드에서 일반적으로 같은 이름의 컬렉션으로 구현된다는 거죠.
    이렇게라도 동작해주면 얼마나 좋겠습니까...만,
    안됩니다.

    TransformGroup.Children이나 Canvas.Children 또는 Canvas.Triggers와 같은 Collection 개체는 일반적으로 하위 개체를 생성하여 추가, 삭제, 접근할 수 있게 되어 있어요.

    하지만 이상하게도 Storyboard의 Children 속성은 분명히 TimelineGroup이라는 이름의 클래스임에도 불구하고 실제로 들어가보면 단지 Timeline을 가리킬 뿐이에요. 다시 말해서 컬렉션이 아니기 때문에 하위 요소를 하나밖에 추가할 수 없다는 얘기죠.

    예제에서 우리는 [오른쪽으로 이동] 이라는 애니메이션과 [360도 회전]이란 애니메이션을 동시에 처리하였죠? 그런데 스토리보드의 Children이 단일 요소만 가리키게 되어 있으니 이건 뭐 방법이 없는 거에요.

    이 부분은 아마도 1.1 Alpha라는 테스트 중인 버전이기 때문에 그렇지 않을까... 정식판이 나오면 스토리보드의 Children이 Animation의 컬렉션으로 변경되지 않을까... 하는 기대를 할 수밖에 없네요.

    XamlReader 클래스를 활용한 동적 스토리보드 작성

    그렇다고 코드에서 스토리보드를 동적으로 생성하고 애니메이션을 추가하는게 불가능한 건 아니에요.
    다만 효율이 조금 떨어질 뿐이죠.

    실버라잇은 XamlReader라는 매우 리버럴한 클래스를 제공하는데요, XamlReader.Load 메서드를 사용하면 파라미터로 전달한 XAML 코드를 동적으로 파싱하여 개체로 반환해주죠.

    예를 들어 새 사각형 개체를 XamlReader를 이용하여 동적으로 추가한다면...

    C#
    string strRect = @"<Rectangle Width='100' Height='100' Canvas.Left='100' Canvas.Top='100' Fill='Red' />";
    Rectangle rect = (Rectangle)XamlReader.Load(strRect);
    this.Children.Add(rect);

    심플하죠? 그냥 동적으로 추가할 XAML 코드를 문자열로 저장하고 XamlRead.Load 메서드의 파라미터로 전달하고 원하는 타입으로 캐스팅만 하면 돼요.

    마찬가지로 스토리보드와 일련의 요소들을 XAML 코드로 작성하여 XamlReader로 동적으로 생성할 수 있다는 거죠.
    처음 Blend로 작성했던 예제를 조금 변형해서 이번엔 텍스트1을 클릭하면 오른쪽으로 100픽셀, 텍스트2를 클릭하면 왼쪽으로 100픽셀을 회전하며 이동하는 코드를 작성해보죠.

    먼저 텍스트1, 2과 결과 확인을 위한 텍스트3을 추가하고 기존에 작성되었던 애니메이션은 제거하며 사각형은 그대로 놔둡니다. 역시 루트 엘리먼트인 Canvas는 생략했으니 주의...
    XAML
    <TextBlock x:Name="text1" Text="You spin me RIGHT round round round..." Canvas.Top="0" />
    <TextBlock x:Name="text2" Text="You spin me LEFT round round round..." Canvas.Top="20" />
    <TextBlock x:Name="text3" Text="O_O" Canvas.Top="40" />


    <Rectangle Width="100" Height="100" Canvas.Left="50" Canvas.Top="100" Fill="Black" RenderTransformOrigin="0.5,0.5" x:Name="rectangle" >
        <Rectangle.RenderTransform>
            <TransformGroup>
                <ScaleTransform ScaleX="1" ScaleY="1"/>
                <SkewTransform AngleX="0" AngleY="0"/>
                <RotateTransform Angle="0"/>
                <TranslateTransform X="0" Y="0"/>
            </TransformGroup>
        </Rectangle.RenderTransform>
    </Rectangle>

    오른쪽/왼쪽으로 움직이는 스토리보드가 하나 있어야겠죠? 클래스의 멤버 변수로 스토리보드를 하나 선언합니다.
    C#
    Storyboard _story = new Storyboard();

    그리고 페이지의 로드 이벤트 핸들러에 텍스트1과 2가 눌렸을 때 처리할 이벤트 핸들러를 추가합니다. 이벤트 핸들러는 아래에서 채워 넣을 거에요.
    C#
    // 텍스트 클릭 이벤트 핸들러 추가
    text1.MouseLeftButtonDown += new MouseEventHandler(text1_MouseLeftButtonDown);
    text2.MouseLeftButtonDown += new MouseEventHandler(text2_MouseLeftButtonDown);

    이제 이벤트 핸들러에 각각 스토리보드를 로드하는 코드를 만들어야겠죠? 이 작업은 앞서 얘기했듯이 수작업으로 머리 싸매가면서 할 필요 없어요. 그냥 Expression Blend로 빈 프로젝트를 하나 만들고 애니메이션 타임라인을 생성하되 새 타임라인을 추가할 때 리소스로 만들기(Create as a Resource)를 선택하세요.


    그리곤 원하는 애니메이션을 대충 만들면 <Canvas.Resources> 태그 내에 맨 처음에 Blend로 만들었던 Storyboard 코드가 만들어질 거에요. 여기에서 <Storyboard>의 x:Name이 Timeline1로 지정되어 있는데 이건 코드에서 동적으로 로드하기 때문에 필요 없으니 삭제하세요. 마지막으로 각 태그의 어트리뷰트 설정을 위해 겹따옴표가 있는데 이건 홑따옴표로 교체하시고 코드-비하인드에 문자열로 붙여넣으시면 다음과 같은 코드가 만들어지죠.
    C#
    void text1_MouseLeftButtonDown(object sender, MouseEventArgs e)
    {
    string strStory =
        @"<Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='rectangle' Storyboard.TargetProperty='(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)'>
                <SplineDoubleKeyFrame KeyTime='00:00:01' Value='100'/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='rectangle' Storyboard.TargetProperty='(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)'>
                <SplineDoubleKeyFrame KeyTime='00:00:01' Value='360'/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>";

        _story = (Storyboard)XamlReader.Load(strStory);
        _story.Completed += new EventHandler(_story_Completed);
        this.Resources.Add(_story);

        _story.Begin();
        text3.Text = "Spin started.";
    }

    void
    _story_Completed(object sender, EventArgs e)

    {
        text3.Text = "Spin completed.";
    }

    text2를 눌렀을 때의 이벤트 핸들러 코드는 생략했어요. (갈수록 날로 먹으려는 이 수작!)
    뭐 text1의 핸들러와 똑같고 두 애니메이션의 Value값을 '0'으로만 바꾸면 되니까 직접 해보세요. -ㅇ-

    여기서 주의할 점은 코드로 제어하는 스토리보드는 반드시 루트 엘리먼트의 리소스로 등록이 되어야 한다는 것과 XamlReader로 동적으로 로드하는 XAML 엘리먼트는 x:Name이 설정되면 안된다는 사실. 잊지 마세요.

    작성된 프로젝트는 다음에 첨부했으니 코딩이 귀찮으신 분들은 다운 받아보세요. :)
    StoryboardTest.zip

    스토리보드 테스트 프로젝트



    동작 데모는 다음과 같습니다.

    http://gongdo.tistory.com/attachment/cfile27.uf@253353395878F57F1002F7.wmv

    여전히 남아있는 불합리성

    여기까지 더운데 땀 삐질삐질 흘려가며 작성하셨다면 지금쯤 꽤나 열이 받으셨을 거에요.

    "블렌드를 써서 만든 코드를 복사해서 도로 붙여 넣고 따옴표 바꿔주고 문자열로 만들고 코드 몇 줄 더 추가하고... 이럴 바에야 스토리보드를 각각에 상황에 맞게 더 만들고 말겠다!"

    네, 정답입니다. 위의 예제 같은 경우는 구태여 코드에서 동적으로 만들 필요성 따윈 전혀 없어요.
    단순한 애니메이션이라면 그냥 Blend를 써서 만드는게 훨씬 빠르고 합리적이죠.

    하지만 이런 경우를 생각해보죠. 만약 애니메이션의 이동 범위가 런타임에 수시로 바뀐다면? 심지어 이동 방향 조차 변경될 수 있다면?
    또는 마우스 커서가 이동하면 마우스 커서에서 시작되는 애니메이션을 만들고 싶다면?

    이럴 때 위와 같이 문자열로 XAML 코드를 옮기되 동적으로 수정하고 싶은 부분을 {0}, {1}, {2} ... 이렇게 치환해놓고 String.Format 메서드로 포매팅하면 되겠죠. 예를 들어 위의 예제에서 진행시간, 이동 범위를 동적으로 변경한다면...
    C#
    string strStory =
        @"<Storyboard>
            <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='rectangle' Storyboard.TargetProperty='(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)'>
                <SplineDoubleKeyFrame KeyTime='{0}' Value='{1}'/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime='00:00:00' Storyboard.TargetName='rectangle' Storyboard.TargetProperty='(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)'>
                <SplineDoubleKeyFrame KeyTime='{0}' Value='360'/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>";

        _story = (Storyboard)XamlReader.Load( string.Format( strStory, new object[] { "00:00:05", "200" } ) );

    이렇게 문자열의 포매팅을 활용할 수 있겠죠.

    휴...
    스토리보드, 애니메이션, 타임라인은 다른 개체들이 상당히 직관적으로 구성되어 있는데 비해 굉장히 난해한 편인 것 같아요. 그냥 개체나 멤버의 이름만 보고 직관적인 코딩이 어렵다는 거죠. 코드만 가지고 적절하게 스토리보드를 만들지 못하고 상당히 지저분한 방법을 동원하게 되었는데요, 다시 얘기하지만 이런 점은 정식판이 나오면서 개선되었으면 하는 바램이에요.

    Posted by gongdo
    http://hoons.kr/SeminarJoin.aspx

    아직 시간이 꽤 남았지만... 훈스닷넷에서 6월 세미나는 패스하고 7월 초에 열립니다.
    기본적으로 WPF 컨퍼런스지만 제도 Silverlight 관련 세션을 맡았으니 관심 있는 분들의 많은 참여를 바래요 :)

    일시 : 2007년 07월 07일(토) 오전 13시 30분
    장소 : 한국 Microsoft 세미나실
    세미나 등록비 : 2.000원 (현장 결제)
    6회 정기 세미나 신청하기 : http://www.hoons.kr/SeminarJoin.aspx 
     
    세미나 Agenda
    13:30~14:00
    등 록
    14:00-14:50
    차세대 웹을 위한 RIA 기술의 이해와 그 미래   / 박경훈 (HOONS닷넷 운영자)
    14:50-14:20
    WPF를 개발하기 위한 툴 소개   / 최우진 (HOONS닷넷 시삽)
    14:20~14:40
    휴식
    14:40~15:10
    How to develop XPS with WPF / 김수영 (HOONS닷넷 시삽)
    15:10~16:00
    실버라이트로 구현하는 포토앨범 / 공도 (유령회사 공도소프트 운영자)
    16:00~16:20
    휴 식
    16:20~16:50
    사이드바 가젯 어플리케이션의 구현 / 김창우(HOONS닷넷 시삽)
    16:50~17:40
    WPF와 WCF로 메신저 만들기 / 서금욱(HOONS닷넷 시삽)
    17:40~
    경 품 추 첨
    발표 내용 소개
    차세대 웹을 위한 RIA 기술의 이해와 그 미래 / 박경훈
    RIA(Rich Internet Application)라는 기술이 차세대 웹의 트랜드라는 말과 함께 빠르게 전파되어 가고 있습니다. 먼저 이번 시간에는 각 벤더의 RIA 기술들을 살펴 봅니다. 그리고 그 기술을 어떤 시각으로 바라보며 어떻게 적용해야 하는 지에 대한 내용을 전해드립니다. 또한 앞으로의 미래의 RIA 기술을 위해서 어떻게 준비해 나가야 할지에 대한 내용을 다룹니다.
    WPF를 개발하기 위한 툴 소개 / 최우진
    WPF를 개발을 위해서 상당히 많은 툴들을 제공하고 있습니다. 이번 시간에는 그 툴들을 살펴보고 어떤 개발에 어떤 툴을 도입해야 되는지에 대한 기초적인 내용들을 살펴 보겠습니다.
    How to develop XPS with WPF / 김수영
    XPS는 MS의 새로운 문서 포맷으로 동적인 무서를 제공할 수 있게 도와 줍니다. 뉴욕타임즈의 XPS 리더기는 이미 많은 사람들로 하여금 그 가치를 느끼게 해 주었고 WPF에서 XPS를 활용할 수 있는 방안도 무궁무진합니다. 이번 시간에는 XPS에 대한 개념과 WPF로 개발하여 활용할 수 있는 방법들을 설명드리겠습니다.
    실버라이트로 구현하는 포토앨범 / 공도
    Silverlight가 MIX'07을 통해 화려한 데뷔를 했지만 국내에서는 찻잔속의 태풍인 것 같습니다. 아마도 새로운 기술에 대한 접근 장벽도 있지만 단순한 문법 소개나 예제 만으로 어떤 애플리케이션을 어떻게 작성해야 하는지 감이 오지 않아서 더욱 그런 것 같습니다. 이 세션에서는 단순한 문법적인 설명이 아니라 실제 프로덕션 수준의 데모를 통해 Silverlight의 가능성과 활용 방안을 제시하고 특히 사용자 컨트롤 구현에 대한 트릭과 팁을 소개합니다.
    사이드바 가젯 어플리케이션의 구현 / 김창우
    기존 웹2.0의 참여와 개방에서 웹 3.0이 화두가 되면서 개인화를 위한 요소가 강조되기 시작했습니다. 그 개인화를 위해서 위젯과 MS의 가젯과 같은 개념들이 등장하게 되었다고 할 수 있습니다. 이번 시간에서는 윈도우 비스타의 사이드바 가젯을 만들고 활용하는 방안들을 설명드리독 하겠습니다.
    WPF와 WCF로 메신저 만들기 / 서금욱
    RIA(Rich Internet Application)라는 기술이 차세대 웹의 트랜드라는 말과 함께 빠르게 전파되어 가고 있습니다. 먼저 이번 시간에는 각 벤더의 RIA 기술들을 살펴 봅니다. 그리고 그 기술을 어떤 시각으로 바라보며 어떻게 적용해야 하는 지에 대한 내용을 전해드립니다. 또한 앞으로의 미래의 RIA 기술을 위해서 어떻게 준비해 나가야 할지에 대한 내용을 다룹니다.
    강사 소개
    박경훈 

    HOONS닷넷 운영자
    Microsoft Visual C# MVP
    김수영 

    (현) 닷넷 프리랜서 개발자
    HOONS닷넷 C# 시삽
    Microsoft Visual C# MVP
    김창우 

    (현) 넥슨 개발자
    인천정보통신 교육센터 전임강사
    RAYPAX - 사내 솔루션/시스템 개발
    HOONS닷넷 C# 시삽
    공도 

    (현) .NET Framework 3.0, 특히 Silverlight에 올인중
    수년간 CTI 업계에 종사(VB6 및 VC6)
    유령회사 공도소프트 운영자(gongdo.tistory.com)
    최우진 

    (현) 주식회사 낱말 재직 중
    독서 지수(Lectio®) 측정 솔루션 개발
    교보 READ 사이트 - 독서력/어휘력 평가 솔루션 개발
    CAT 기반 독서력 측정 사이트 작업 중
    MCP(켁~), CCNA, 정보처리기사 \BK21
    대전.충남지역 대학생 학술 경연 대회 금상 수상 (Virtual My Home 3D)
    김창우 

    (현) 넥슨SD 개발지원팀/
           월간 마이크로소프트웨어 기사기고
    (개발)
    - 해석모델 관리시스템(CAES)
    - 핼프데스크(Groupware)
    - 도면관리 시스템개발
    - 시작차 작업 관리 시스템(PWMS) - 아이템25 개발
    세미나 장소

    [포스코 센터에 오시는길 : 포스코 센터 서관 5층]
    경품안내

    HOONS 닷넷과 함께하는 .NET Framework 3.0(박경훈,서동진) - 2권


    C# 프로그래밍 바이블 with .Net Framework3.0(최재규) - 3권


    게시판과 블로그 예제로 배우는 ASP.NET 2.0(김상훈) -2권
    세미나 후원
     
    Posted by gongdo

    바로 아래에 검색 팁을 포스팅해놓고 좀 뻘쭘하지만...
    오늘도 검색을 게을리 했다가 당한 얘기를 좀 해야겠네요.

    스토리보드와 애니메이션 개체를 동적으로 생성하여 이것을 코드만으로 제어하는 걸 근 하루째 삽푸고 있었어요.

    음... 요즘 퀵스타츠나 기본 학습 포스팅이 게을러져서 아직 다루진 않았지만 어쨌든 Storyboard는 xxxAnimation 개체들을 포함하고 Storyboard.Begin을 호출하면 이 애니메이션들을 재생할 수 있지요.

    여기에서 애니메이션은 대상 개체의 이름(Target Name)과 그 개체의 대상 속성(Target Property)를 설정해줘야 합니다.
    예를 들면 캔버스 개체의 RotationTransform(회전 변형 속성).Angle(각도) 와 같은 것 말이죠.

    그런데 대상 개체의 이름 즉, XAML에서 x:Name 으로 설정되는 속성은 코드-비하인드에서 해당개체.Name 속성으로 읽기는 가능하지만 쓰기가 불가능해요.
    따라서 XAML에서 생성된 개체가 아니라 코드로 동적으로 생성한 개체 예를 들어, Canvas panel = new Canvas(); 이렇게 생성한 개체는 Name 속성이 공백으로 식별이 불가능한 상태가 되죠.

    ...네 이런 사실을 알아내기까지 온갖 삽을 푸면서 거의 하루가 걸렸는데 검색해보니 한방에 걸리네요.

    http://silverlight.net/forums/p/1335/3133.aspx

    여기에 보면 친절하게도 Microsoft의 미스터 막이 직접 답변 했는데...
    '지금 당장 1.1 Alpha(나 1.0 Beta)에선 프로그래미컬하게 Name속성을 못바꿔. 일찌감치 포기하고 XamlRead.Load를 사용해서 XAML 리소스에서 읽어오도록 혀. x:Name 설정하는거 잊지말고 내말 알아듣지?'

    그 아래에는 또...
    '나중에(당연히 언제라고는 얘기 안하고) 1.1 정판이 나오면 Name을 설정할 수 있을테니껭 기둘리...'
    라는군요.

    ...후우...

    다시 한번 강조하지만 뭔가 막힌다... 어 이거 뭐지? 란 생각이 든다... 주저없이 검색 먼저 하세요. 검색하는데 5분도 안걸렸고 위의 문장 해독해석하는데 15분 밖에(...) 안걸렸어요.
    반면 삽을 푸는건 거의 하루는 걸렸죠.

    다시 한번 에브리바디~ 검색의 생활화~ 예!

    Posted by gongdo
    뭐 비단 실버라잇 뿐만 아니라 대부분의 개발시 적용되는 내용이에요.

    기본적으로 많이 알려지고 많은 사람들이 사용하는 언어(예를 들어, VB, C, Java, C#, 플래쉬 등)는 먼저 한글 사이트를 찾아보는게 빨라요.

    MS 계열의 기술일 경우엔 Devpia(http://devpia.com/)나 고수닷넷(http://www.gosu.net/GosuWeb/Home.aspx) 이 가장 활성화 된 커뮤니티이고 다음으론 네이버 카페도 무시할 수 없을 정도의 규모를 가지고 있죠.

    그런데 이런 커뮤니티들은 대부분 회원 가입이 필요해서 저 처럼 회원가입에 거부감을 보이는 사람들에겐 그닥 좋은 수단이 못되는 것 같아요.

    다음으로 WPF나 실버라이트처럼 많이 알려지지 않거나 사용자가 적거나 하는 경우엔 국내에서 쓸만한 자료를 찾는건 거의 가능성이 없어요. 그나마 각종 커뮤니티에 수소문 해보는 방법도 있지만 시간 낭비가 심하죠.

    그럴 때 개발자라면 필수적으로 끼고 살아야할 구글이 있죠! 단, 영문이니까 눈알 빠지도록 고생해야 한다는 건 슬픈 현실...

    예를 들어 실버라잇으로 타이머 구현을 어떻게 해야하나... 한번 검색해보죠
    구글 여시고, Silverlight Timer 라고 검색해보세요.


    결과가 너무 많네요? 이래서야 원하는 정보 찾기가 어렵겠죠.
    그럼 좀 더 실버라잇에 관련된 정보가 집약된 사이트로 대상을 한정해보죠.
    외국의 경우엔 상당히 깊이 있는 정보를 오픈된 포럼이나 블로그에서 얻을 수 있는 경우가 많아요. 실버라잇은 공식 사이트인 silverlight.net/forum 에서 사용자들의 질문과 답변, 의견들이 오가는데요, 한번 검색해보죠.
    silverlight timer site:silverlight.net


    제목만 봐도 뭔가 타이머 구현에 대한 내용이 있을 것 같지 않나요?
    실제로 첫번째 링크에 들어가보면 대략 'Q : 내가 타이머 구현하고 싶은데 어케해야됨?' 'A : 어... 그거랑 관련해서 좋은 링크 있으니까 타고 들어가봐'
    이런 내용이 있고 링크 타고 가보면 어떤 블로그에서 그에 대한 솔루션을 제시하고 있는 걸 볼 수 있어요.

    물론 모든 이슈에 대해 정보가 있는건 아니지만 대체로 작업하다 막히는 내용이 있다면 분명 다른 사람도 그렇게 막힐 때가 있었을테고 일반적인 상황에 대한건 대부분 검색에서 걸리더군요.

    구글 검색에서 특히 site: 한정자는 많이 사용하는데요, 제 경우는 특히 site:microsoft.com, site:msdn.microsoft.com, site:msdn2.microsoft.com 을 자주 이용하는 편이에요.

    개념 적인 샘플 코드 말고 뭔가 실제로 해볼 수 있는 프로젝트 수준의 샘플을 찾는다면?
    그럴 땐 좀 더 전문적인 커뮤니티를 찾아야겠죠.

    제가 즐겨 찾는 곳은 코드플렉스(http://www.codeplex.com/)와 코드프로젝트(http://www.codeproject.com/index.asp)이고 그 외에는 주로 구글 검색으로 타고 들어가는 경우가 많아요.


    마지막으로 실버라잇으로 구현하다가 막히는 부분, 궁금한 부분은 블로그의 어디에라도 덧글을 남겨주시면 좋은 일이 있을 지도 몰라요 ^^
    Posted by gongdo
    네이버의 실버라이트 카페에 정말 알기 쉬운 튜토리얼 모음집이 올라왔습니다.
    수고하신 패러다임님께 박수를... ^^
    http://cafe.naver.com/mssilverlight.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=77

    실버라이트를 처음 시작하시는 분이라면 위의 튜토리얼 먼저 시작하시는게 좋을 것 같네요.
    위의 주소에 들어가서 파일을 다운 받으시고 압축 풀고 index.html을 열어보시면 다음과 같은 화면을 볼 수 있어요.



    Silverlight 1.0 Beta의 Quickstarts를 기준으로 단계별로 학습을 진행하시면 될 것 같네요. ^^
    Posted by gongdo
    아... 이런 걸 볼때마다 잘 나가던 의욕이 뚜~~~욱 떨어지는 소리가 들려요.
    뭐 누군가 만들지 않을까 생각은 했지만 참 빨리도 나오네요...

    바로 실버라잇에서 구현하는 3D 개체.
    코드플렉스에서 현재 Balder라는 코드명으로 진행중에 있는 듯 하군요.


    데모는 아래에서...
    http://www.dolittle.com/Silverlight/3D/TestPage.html

    프로젝트 메인 주소는
    http://www.codeplex.com/Balder

    소스 코드는 한숨 자고 일어나서 봐야겠습니다. 다시 리뷰 할께요 :)
    Posted by gongdo
    싱글스레드 프로그래밍에서 비동기 실행에 필수적인 것, 바로 타이머죠.
    Silverlight는 자체적으로 타이머 클래스를 지원하고 있지 않지만 약간의 트릭을 사용하여 타이머를 만들 수 있습니다.

    다음에 설명할 예제는 아래에서 다운받을 수 있고요
    TimerTest.zip

    타이머 클래스 데모



    동작 데모는 아래 사이트에서...
    http://gongdo.oranc.co.kr/Silverlight/Samples/TimerTest/TestPage.html

    Storyboard 트릭

    타이머 지원의 핵심은 바로 Storyboard!
    Silverlight의 Storyboard는 대상 Animation이 없더라도 지정된 시간 동안 스토리를 진행하고 이벤트를 띄워주는 구멍 아닌 구멍을 가지고 있죠. 바로 이런 점을 이용하여 빈 스토리 보드를 리소스로 추가하고 Begin시킨 다음, Completed 이벤트가 발생하면 또다시 Begin시키고 또 Completed되었을 때 Begin하는 방식이에요. XAML 코드의 예를 들자면...

    XAML
    <Canvas.Resources>
        <Storyboard x:Name="timer" BeginTime="00:00:00.000" Duration="00:00:01.000" Completed="OnTimer" />
    </Canvas.Resources>

    그리고 코드-비하인드에는 이 스토리 보드를 Begin시킬 코드와 Completed 되었을 때 처리할 이벤트 핸들러가 필요하겠죠. 이 이벤트 핸들러에서 스토리보드를 다시 시작하면 일정한 간격으로 계속 해서 이벤트가 발생하는 타이머 효과를 얻을 수 있죠.
    C#
    void OnTimer(object sender, EventArgs e)
    {
        // 스토리보드의 Duration이 지나 종료됨, 다시 스토리보드 시작
        ((Storyboard)sender).Begin();
    }

    매니지드 코드만으로 구현하는 타이머

    그런데, 타이머가 필요할 때마다 XAML을 사용하여 리소스에 등록하는 일은 아주 귀찮은 일이죠. 그냥 Timer tmr = new Timer(); 이런 깔끔한 문장으로 타이머를 만들 수 있다면 얼마나 좋겠어요?
    C# 매니지드 코드만으로 Storyboard 생성하는 방법
    Storyboard story = new Storyboard();
    story.BeginTime = TimeSpan.Zero;
    story.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 500));
    story.Completed += new EventHandler(story_Completed);

    위의 코드는 새 스토리보드의 인스턴스를 생성하고 시작시간(BeginTime)을 Zero로 설정하고 진행 기간을 500ms로 설정한 후 Completed 이벤트 핸들러를 추가해줬습니다. 한 가지 주의 깊게 볼 것은 Duration은 Duration 클래스로 표현되고 Duration의 오버로드된 생성자에 TimeSpan 개체를 넣어주면 되지요.

    TimeSpan은 또 뭐냐구요? 시간과 시간의 간격을 나타내는 클래스인데 다른건 몰라도 그냥 생성자에 날짜, 시간, 분, 초, 밀리초를 집어 넣으면 해당 시간 만큼의 간격 값이 저장된다고 생각하시면 돼요.

    참 쉽죠?

    그런데, 이게 다가 아니에요. 스토리보드는 반드시 어떤 개체의 트리거로 연결되거나 어떤 XAML 페이지의 탑레벨 엘리먼트 즉, 루트 엘리먼트의 Resource로 등록이 되어야만 정상적으로 동작해요.

    예를 들어 MainPage.xaml의 코드-비하인드에서 위의 story를 리소스로 추가한다면 this.Resources.Add(story); 라는 단순한 구문으로도 가능하죠.

    하지만 조금만 더 생각해봐요. 범용적인 Timer 클래스를 만드는데 위와 같이 하면 항상 메인 XAML에 대한 코드-비하인드에 Timer 코드를 복사해서 넣는 건 정말로 불합리하잖아요?

    따라서 Timer를 클래스화 한다면 다음과 같이 클래스의 생성자에는 스토리보드가 추가될 메인 XAML의 루트 엘리먼트에 대한 참조를 넘겨주는 코드가 필요할 거에요.
    C#
    public Timer(FrameworkElement rootElement)
    {
        rootElement.Resources.Add(story);
    }

    그런데 이게 끝이 아니에요. 또 뭔가 싶죠?
    위의 클래스는 약점이 있는데 바로 클래스 초기화 인자로 받는 rootElement가 진짜로 ROOT인지 확인을 하지 않는 다는 점이에요.
    클래스 설계시 주의할 점 중에 하나는 '사용자는 반드시 잘못된 인자를 넘겨준다.'라고 생각해요.
    rootElement의 타입이 FrameworkElement라서 FrameworkElement이기만 하면 TextBlock을 넘기든 Rectangle을 넘기든 이 코드는 똥인지 된장인지 구분 못하고 넙죽 받아먹는다는 거죠.

    좀 더 안전한 코드를 작성하기 위해 다음과 같은 함수로 어떤 FrameworkElement에 대한 최상위 Element 즉, 진짜 Root 엘리먼트를 받을 필요가 있습니다.
    C#
    // 혹시 모를 사용자 실수를 대비하여 해당 엘리먼트의 절대적인 루트 엘리먼트를 반환
    private FrameworkElement AbsoluteRootElement(FrameworkElement element)
    {
        FrameworkElement root = element;
        // 최상위 엘리먼트라고 판단 될때까지 부모 엘리먼트를 얻기
        while(root.Parent != null)
        {
            root = (FrameworkElement)root.Parent;
        }
        return root;
    }

    약간 복잡한 것 같지만 단계별로 잘 생각해보면 어렵지 않아요.
    작성한 Timer 클래스의 완성본은 첨부한 프로젝트를 참고하시고 다음은 동작 데모 동영상.


    http://gongdo.tistory.com/attachment/cfile25.uf@2101C1335878F5791FC106.wmv


    참고
    http://silverlightrocks.com/community/blogs/silverlight_games_101/archive/2007/05/15/creating-a-game-loop.aspx
    실버라이트로 게임을 구현하려는 블로그... 하지만 업데이트가 안 되는 것 같네요 -_-
    Posted by gongdo
    관련글 : [초등2 겨울방학 숙제팁]silverlight 밑바닥 기본기 정리

    드디어 기다리고 기다리던 낙훈님의 예술 작품이 완성되어 세상의 빛을 받았네요!


    위의 스샷은 낙훈님의 실물 사진(예상도) ㄲㄲㄲ...

    아 진짜 프로그래밍 6년 하면서 이런 센스 만점의 데모는 처음이에요.
    Posted by gongdo
    요즘 세미나 발표를 하나 맡아서 의욕에 불타오르고 있네요.
    덕분에 QuickStarts는 약간 보류. 아마 이번달 셋째주 이후로 한꺼번에 포스팅하지 않을까 싶습니다.

    오늘은 이미지 로딩에 대해서 이런저런 테스트를 하다가 분노의 허리띠춤을 출 정도로 화났었죠.

    어떤 개체를 이미지로 칠할 수 있는 ImageBrush라는 아주 막강한 툴을 제공하면서 이미지를 반복적 패턴으로 깔 수 있는 TileMode를 지원하지 않는 허무한 점.
    이건 뭐;; 만약 10x10 사이즈의 패턴이 있고 이걸 100x100 영역에 바둑판 형식으로 깔고 싶다면 10x10=100개의 동일한 패턴 이미지를 생성해서 배열해야한단 얘기죠.

    여기서 약간의 머리를 굴려서 패턴 이미지를 한번만 다운받아놓고 이걸 100개의 Image 개체에서 소스를 공유하면 비교적 간단하면서도 리소스 효율적으로 되지 않겠는가...란 생각으로 테스트 코드를 쓱쓱 작성했죠.

    그런데 Image개체의 SetSource로 설정하는 Downloader는 한번 SetSource의 대상이 되면 다른 이미지의 SetSource에 대응하지 못하는 것 같습니다. ImageBrush도 마찬가지고요.

    아니 그럼 똑같은 이미지를 100개 다운받아서 쓰란 얘긴가!?

    이쯤되면 열받죠. 위의 테스트를 진행하는 것도 한나절 걸렸는데 방법이 없으니 너무나도.

    그런데.
    그냥 막코딩해도 성능이 충분히 나오는거에요.
    Image[] img = new Image[100];
    for (int i=0; i<100; ++i)
    {
        img[i] = new Image();
        img.Source = new Uri(”Large.jpg”);
    }

    이런식으로 100개의 이미지 개체를 생성하고 100개의 new URI로 소스를 설정해도 실버라잇이 알아서 캐슁하는 것 같습니다.

    각 단계에서 걸리는 시간을 측정해보면 첫번째 이미지를 초기화 하는데 약간 시간이 더 걸리고 나머지 99개는 거~의 상수시간 이내에 처리가 되는군요.

    상당한 크기의 이미지(2304x1728 픽셀, 1.61메가) 100개를  리사이징 없이 올려놨는데도 정말 좋은 효율로 동작하네요. 메모리도 1.61메가 x 100 만큼 먹는게 아니라 원래 실버라잇 런타임이 먹는 용량 + 알파 정도... 총 합계 약 20메가 정도 먹습니다. 다시 말해 동일한 이미지를 메모리에 또 올리는 바보짓은 안한다는 거죠.

    테스트는 여기에서 해보실 수 있어요.
    http://gongdo.oranc.co.kr/Silverlight/Samples/DownloadTest/TestPage.html

    역시나 뭘 해도 저보다야 100만배쯤 똑똑한 사람들이 만든거라... 후우... 오늘 난 뭘 위해 삽질을 했나. 그냥 막코딩을 해도 성능 충분히 나오는데...-_-
    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    HTML DOM의 사용
    준비 사항
    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
    <Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="HtmlDom.Page;assembly=ClientBin/HtmlDom.dll"
        Width="300" Height="50" Background="#FFFF9966">
        <TextBlock Text="Access HTML DOM from managed code." />
    </Canvas>

    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/
    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    디버깅과 예외 처리
    준비 사항
    Silverlight 개발의 기초에서 개발에 필요한 도구와 기술에 대해 설명하고 있습니다.
    이벤트 핸들링에서 개체의 이벤트를 처리하는 방법에 대해 설명하고 있습니다.
    커스텀 컨트롤에서 개발 프로젝트에 테스트 프로젝트를 추가하는 방법을 소개하고 있습니다.

    기본적으로 Visual Studio IDE를 사용한 .Net 프로그래밍 및 디버깅 방법과 유사하므로 Visual Studio IDE를 사용한 보다 전문적인 디버깅은 Visual Studio의 디버깅을 참고하십시오. 이 글에서는 간단한 기법만을 소개합니다.

    또한 ASP.NET 프로젝트와 IIS에 대한 언급도 나옵니다. 이 부분은 지금 곧 사용하지 않는다면 특별한 사전 지식은 필요 없습니다.

    매니지드 코드 디버깅

    일반적인 브레이크 포인트를 사용한 디버깅
    매니지드 코드의 디버깅은 일반적인 .Net 프로그래밍에서의 그것과 동일합니다. 가장 기본적인 디버깅 방법으로 브레이크 포인트를 걸고 런타임에 해당 코드가 실행되기 직전에 코드의 실행을 멈추고 콜스택이나 멤버 변수 등의 값을 살펴볼 수 있습니다.

    우선 매니지드 코드 디버깅 예제를 위해 새 프로젝트를 생성하고 일부러 틀린 코드를 넣어보겠습니다.
    Howto:4-1 새 프로젝트에 잘못된 코드 작성하기
    1. 새 프로젝트를 생성합니다. (프로젝트를 생성하는 방법은 Silverlight 개발의 기초를 참고하십시오.)
    2. Page.xaml.cs의 Page 클래스에 다음과 같은 멤버 함수를 작성하고 Page_Loaded에서 해당 함수를 호출합니다.
    C#
    private void WrongMethod()
    {
        TextBlock tb = new TextBlock();
        Run run = new Run();
        run.Text = "Test text";
        tb.Inlines.Add(run);
        this.Children.Add(tb);
    }

    위의 코드를 언뜻 보면 새 TextBlock 개체를 생성하고 TextBlock에 Run 텍스트를 하나 추가한 후 TextBlock을 페이지의 자식 개체로 추가하는 정상적인 코드처럼 보입니다. 아마도 개발자는 화면에 Test text 란 메시지가 출력되길 기대하고 있을 것입니다.

    하지만 F5를 눌러 위의 코드를 디버그 모드로 실행해보면 화면에는 아무것도 나오지 않으며 다만 Output 창에는 예외가 발생했다는 메시지가 보입니다.


    문제가 발생하는 시점을 찾기 위해 브레이크 포인트를 걸고 차근차근 진행해 보겠습니다.
    Howto:4-2 브레이크 포인트 걸고 진행하기
    1. 어디에서 문제가 생겼는지 확실치 않으므로 처음부터 브레이크 포인트를 설정합니다. 첫 문장인 TextBlock tb = new TextBlock() 코드에 커서를 맞추고 F9를 누르거나 해당 라인의 제일 왼쪽의 회색 공간을 클릭하여 브레이크 포인트를 설정합니다.


    2. F5를 눌러 디버그 모드로 실행하면 다음과 같이 브레이크 포인트에서 코드 실행이 멈춥니다.


    3. F10을 눌러 한 라인 단위로 진행합니다. (※노트: 함수 내부까지 들어가서 진행하려면 F11을 눌러 진행합니다.)

    4. 아마도 tb.Inlines.Add(run); 문장을 진행하면 Output 창에 예외가 발생하였다는 메시지와 함께 디버깅이 중지되고 미완성된 페이지가 브라우저에 나타날 것입니다.

    5. Shift + F5를 누르거나 디버깅 중인 브라우저를 닫아 디버깅 모드를 완전히 종료합니다.

    6. 4번 과정을 실행하는 중 예외가 발생하였으므로 이 부분의 코드가 잘못되었다는 것을 알 수 있습니다. 또한 예외 메시지를 살펴 보면 [A first chance exception of type 'System.NullReferenceException' occurred in DebugManagedCode] 즉, 예외의 종류가 System.NullReferenceException임을 알 수 있고 자연스럽게 null을 참조하여 발생한 문제라는 것도 예상할 수 있습니다.

    7. 다시 한번 디버깅을 진행하여 주의 깊게 진행하고 4번 과정에서 진행하지 않고 멈춰서 tb.Inlines 부분에 마우스 커서를 맞추면 다음과 같이 상세 정보를 볼 수 있습니다. 예상대로 tb.Inlines 멤버가 null을 참조하고 있으며 따라서 Inlines의 멤버 메소드인 .Add를 접근할 수 없음을 알 수 있습니다.
     

    위의 시나리오는 비교적 간단하고 사소한 실수이지만 코드를 작성할 때 빈번하게 발생하는 문제이기도 합니다. 보통 코드를 작성하고 최초로 테스트 할 때에는 위와 같이 새로 작성한 코드에 브레이크 포인트를 설정하여 한 라인씩 진행하면서 코드가 예측한대로 작동하는지 검사하곤 합니다.

    Visual Studio IDE는 디버그 모드상에서 어떤 개체에 대해 매우 직관적이고 상세한 정보를 실시간으로 볼 수 있는 인터페이스를 제공하고 있습니다. 각 개체는 자신의 멤버 뿐만 아니라 자신의 상위 개체에 대한 정보도 볼 수 있습니다.

    브레이크 상태에서 코드를 직접 실행하기
    브레이크가 걸린 상태에서 IDE에는 직접 실행 창(Immediate Window)이 나타납니다. 이 직접 실행 창에서는 현재 코드 상태에서 멤버의 값을 변경하거나 읽어오는 등 즉시 코드를 실행할 수 있습니다. 특히 임의의 식(expression)을 테스트 해볼 수도 있어서 디버깅에 매우 유용한 툴입니다.

    Howto:4-3 직접 실행 창에서 디버깅 하기
    1. 이전 예제를 디버깅 모드로 실행하고 브레이크 상태를 만든 후 문제의 코드까지 진행합니다. IDE의 하단에서 직접 실행 창(Immediate Window) 탭을 찾아 엽니다.

    2. 직접 실행 창에 다음과 같이 입력하고 엔터를 눌러 tb.Inlines의 값을 확인해 봅니다.
    Immediate Window
    ? tb.Inlines.ToString();


    tb.Inlines가 null임을 확인할 수 있습니다. 여기에서 '?'는 직접 실행 창에 그 결과를 출력하라는 의미입니다.

    3. 직접 실행 창에 다음과 같이 입력하고 엔터를 눌러 tb.Inlines의 새 인스턴스를 할당해 봅니다.
    Immediate Window
    tb.Inlines = new Inlines();



    4. 개체 참조가 변경되었는지 확인하기 위해 다시 한번 tb.Inlines의 내용을 출력해봅니다.


    5. F5를 눌러 코드를 계속 진행합니다. 아까와는 다르게 예외가 발생하지 않고 정상적인 출력이 된 것을 확인할 수 있습니다.


    직접 실행 창을 사용하면 런타임 도중에 문제가 생겼다고 예상되는 지점에서 직접 코드를 테스트해볼 수 있습니다. 여기에서 이미 작성된 코드 뿐만 아니라 위의 예제와 같이 new 연산자 등을 통해 개체의 새 인스턴스를 생성하는 것도 가능하며 코드와 전혀 관계 없는 수식 등도 사용할 수 있습니다.

    예외 처리
    브레이크 포인트와 직접 실행 창을 사용한 디버깅은 개발 초기에는 문제점을 찾기에 매우 유용하지만 애플리케이션이 배포되고 난 후에는 전혀 도움이 되지 않습니다. 애플리케이션은 미처 수정하지 못한 문제점이 있기 마련이며 코드가 완벽하더라도 외부 환경적인 요인으로 인해 문제가 발생할 수도 있습니다.

    예를 들어, 외부 리소스 XAML 파일의 스트림을 읽어오는 코드를 생각해보면 이 XAML 파일은 외부 컨텐츠이므로 해당 경로에 존재하지 않을 수도 있을 것입니다. 이렇게 동적으로 상태가 변경될 수 있는 가능성이 있는 코드는 반드시 예외 처리를 할 필요가 있으며 Silverlight 매니지드 코드에서는 전통적인 try~catch~finally문을 지원합니다.
    Howto:4-4 예외가 발생할 수 있는 코드를 위한 try~catch 예제
    1. Page.xaml.cs에 다음과 같이 System.IO 네임스페이스를 추가합니다.
    C#
    using System.IO;

    2. Page 클래스에 다음과 같은 멤버 메소드를 작성하고 Page_Loaded에서 해당 메소드를 호출하는 코드를 추가하고 이전 예제인 WrongMethod() 호출은 주석처리 합니다.
    C#
    private void ExceptionalMethod()
    {
        StreamReader sr = null;
        try
        {
            sr = new StreamReader("test.xaml");
            Brush dynamicBrush = (Brush)XamlReader.Load(sr.ReadToEnd());
            sr.Close();
        }
        catch (Exception ex)
        {
            string err = ex.Message;
        }
    }

    3. 프로젝트 폴더에 test.xaml이란 파일은 존재하지 않으므로 예외가 발생하고 catch 될 것을 예상할 수 있습니다. string err = ex.Message; 문장에 브레이크 포인트를 설정하고 F5를 눌러 프로젝트를 디버깅 모드로 실행해 봅니다.

    4. IDE상의 직접 접근과 직접 실행 창 등을 통해 예외 정보 개체인 ex를 통해 예외의 정보에 접근할 수 있습니다.

    코드에서 예외가 발생하면 그 다음 문장은 실행되지 않고 코드가 중지되어버리기 때문에 웹 애플리케이션의 관점에서 최악의 상황이라고 할 수 있습니다. 따라서 런타임 중 예외가 발생할 가능성이 있는 코드는 반드시 위와 같은 try~catch 문을 사용하여 예외가 발생했을 때 애플리케이션이 그냥 중지되어버리지 않도록 처리할 필요가 있습니다.

    브레이크 포인트를 걸지 않고 정보 출력하기
    매우 빈번하게 진행되는 코드의 디버깅을 브레이크 포인트로 한 줄씩 실행한다는 것은 너무나도 소모적인 일입니다. 보다 효율적인 디버깅을 위해 Silverlight는 System.Diagnostics 네임스페이스에 포함된 Debug 클래스를 제공합니다.


    이 클래스는 디버깅 도중 브레이크 포인트를 걸지 않고도 Output 창에 문자열을 출력할 수 있는 WriteLine 메소드를 지원하며 WriteLine 메소드는 콘솔 애플리케이션의 Console.WriteLine 메소드와 동일한 사용법을 가졌습니다.
    노트
    아쉽게도, 매우 강력한 디버깅 도구인 Debug.Assert는 현재 제대로 작동하지 않는 것으로 보입니다. Assert는 코드의 전제 조건을 강제하고 조건이 실패하는 경우 코드의 실행을 멈추고 지정한 메시지를 출력하는 역할을 수행하는 메소드입니다. 하지만 Silverlight 1.1 Alpha(2007.5 CTP) 현재는 Assert에 어떤 조건을 걸어도 별도의 리액션이 발생하지 않습니다.

    Howto:4-5 Debug.WriteLine 메소드
    1. Page.xaml.cs에 다음과 같이 System.Diagnostics 네임스페이스를 추가합니다.
    C#
    using System.Diagnostics;

    2. Page 클래스에 다음과 같은 멤버 메소드를 작성하고 Page_Loaded에서 해당 메소드를 호출하는 코드를 추가하고 이전의 두 예제 메소드는 주석처리 합니다.
    C#
    private void OutputMethod()
    {
        int sum = 0;
        for (int i = 1; i <= 100; ++i)
        {
            sum += i;
            Debug.WriteLine("i = {0}, sum = {1}", i, sum);
        }
        Debug.WriteLine("Total = {0}", sum);
    }

    3. F5를 눌러 실행합니다. IDE의 Output 창에 다음과 같이 출력되었음을 확인할 수 있습니다.

    지금까지 테스트했던 프로젝트를 첨부하였습니다.
    DebugManagedCode.zip

    매니지드 코드 디버깅



    웹 프로젝트와 Silverlight 프로젝트를 함께 디버깅

    Silverlight는 JavaScript를 사용하여 HTML 페이지에 호스트되는 클라이언트 사이드 애플리케이션이기 때문에 서버 사이드는 어떤 언어를 사용하여도 상관 없습니다. 하지만 Silverlight 컨트롤을 ASP.NET 페이지에 호스팅하도록 개발한다면 하나의 개발환경과 CLR을 통해 제공되는 일관된 언어 사용의 장점을 얻을 수 있을 것입니다.

    이때 Silverlight 컨트롤이 자신을 호스팅하는 ASP.NET 페이지와 상호작용이 많다면 ASP.NET 페이지와 Silverlight 컨트롤의 코드를 함께 디버깅할 수 있으면 편리할 뿐더러 생산성도 대폭 향상될 것입니다.

    이 절에서는 ASP.NET 웹 프로젝트에서 Silverlight 프로젝트를 추가하여 함께 디버깅하는 방법을 알아보겠습니다.

    먼저 아주 간단하게 Hello Silverlight!를 출력하는 Silverlight 프로젝트를 하나 작성합니다. 이제 프로젝트 작성에 익숙해졌으리라 믿고 생성하는 방법은 생략하겠습니다. 프로젝트 이름은 HelloSilverlight라고 하겠습니다.
    Howto:4-6 웹 프로젝트와 Silverlight 프로젝트를 링크하고 디버깅하는 방법
    1. Visual Studio를 실행하고 메뉴에서 File->New->Project를 선택하거나 Ctrl+Shift+N을 눌러 새 프로젝트를 선택합니다.

    2. Project Type에서 Visual C#->Web을 선택하고 Templates에서 ASP.NET Web Application을 선택한 후 프로젝트 이름을 MixedModeDebug라고 적고 [OK]를 누릅니다.
    사용자 삽입 이미지


    3. 솔루션 익스플로러의 솔루션 아이템에서 마우스 오른쪽 버튼을 누르고 Add->Existing Project를 선택합니다.


    4. 미리 만들어둔 HelloSilverlight 프로젝트를 선택합니다. 솔루션 익스플로러에 이제 두개의 프로젝트가 포함될 것입니다.

    5. 솔루션 익스플로러의 MixedModeDebug 웹 프로젝트에서 마우스 오른쪽 버튼을 누르고 Add Silverlight Link를 선택합니다.


    6. 목록에 HelloSilverlight가 있을 것입니다. 선택하고 [OK]를 누릅니다.


    7. 이 프로젝트를 위한 Silverlight 디버깅을 활성화 하겠냐고 묻는 창이 나옵니다. [예]를 누릅니다.
    사용자 삽입 이미지

    중요
    이 설정은 스크립트 디버깅을 비활성화 상태로 설정합니다. Mixed-mode 디버깅을 사용하는 상태에서 매니지드 코드와 언매니지드 코드(스크립트)를 동시에 디버깅 할 수 없습니다.

    8. 다음과 같이 MixedModeDebug 웹 프로젝트에 ClientBin과 Page.xaml 파일이 복사되었음을 확인할 수 있습니다.


    9. Page.xaml을 ASP 페이지로 로드하기 위해 Silverlight.js와 createSilverlight 함수를 프로젝트로 추가합니다. 실제 프로젝트에서 Silverlight.js는 아마 웹서버의 공용 include 폴더에 위치할 것이며 createSilverlight 함수는 각 XAML 파일마다 하나씩 존재할 것입니다. 여기에서는 빠른 진행을 위해 HelloSilverlight 프로젝트의 Silverlight.js와 createSilverlight 함수가 포함된 TestPage.html.js 파일을 프로젝트로 추가하고 MixedModeDebug 웹 프로젝트의 Default.aspx에 위 스크립트 파일들을 include하고 Page.xaml을 로드할 것입니다.

    솔루션 익스플로러의 MixedModeDebug 웹 프로젝트에서 마우스 오른쪽 버튼을 누르고 Add Existing Item을 선택하고 HelloSilverlight 프로젝트의 Silverlight.js 파일과 TestPage.html.js 파일을 선택합니다.



    10. 다음과 같이 MixedModeDebug 웹 프로젝트에 해당 파일이 복사되었음을 확인할 수 있습니다.


    11. HelloSilverlight 프로젝트의 TestPage.html 파일을 열어 스크립트를 include 하는 부분과 XAML을 로드하는 HTML 코드를 복사하여 MixedModeDebug 웹 프로젝트의 Default.aspx파일에 붙여넣습니다.
    사용자 삽입 이미지


    12. 양쪽 프로젝트에 모두 브레이크 포인트가 잡히는지 확인하기 위해 MixedModeDebug 웹 프로젝트의 Default.aspx.cs 파일에서 Page_Load 메소드에 브레이크 포인트를 설정하고 HelloSilverlight 프로젝트의 Page.xaml.cs 파일에 Page_Loaded 메소드에 브레이크 포인트를 설정합니다.


    13. Ctrl+Shift+B 또는 F6을 눌러 솔루션을 빌드하고 F5를 눌러 디버깅 모드로 실행해 봅니다.
    이때 Web.config 파일에 디버깅이 활성화되지 않았다는 메시지가 나올 것입니다. [Modify Web.config file to enable debugging.]을 선택하고 [OK]를 누릅니다.


    14. 정상적인 경우 MixedModeDebug 웹 프로젝트의 Default.aspx.cs 파일에 먼저 브레이크가 걸리고 계속 진행하면 HelloSilverlight 프로젝트의 Page.xaml.cs 파일에 브레이크가 걸릴 것입니다.

    웹 프로젝트에서 JavaScript 디버깅

    앞서 소개한 디버깅 기법으로 웹 프로젝트와 Silverlight를 통합된 환경에서 디버깅할 수 있지만 이렇게 할 경우 다른 JavaScript 등의 스크립트 디버깅 기능은 사용할 수 없게 됩니다. 이 절에서는 이 전 절의 솔루션 상태에서 Silverlight 디버깅을 제거하고 JavaScript 디버깅을 하는 방법에 대해 알아보겠습니다.
    Howto:4-7 웹 프로젝트에서 JavaScript 디버깅하는 방법
    1. 먼저 인터넷 익스플로러를 디버깅 가능한 상태로 설정해야 합니다.
    인터넷 익스플로러의 도구 메뉴에서 인터넷 옵션을 선택합니다.

    2. 고급 탭에서 '스크립트 디버깅 사용 안 함(Internet Explorer)'의 체크를 해제합니다. 만약 다른 브라우저로도 디버깅하려면 '스크립트 디버깅 사용 안 함(기타)'의 체크도 해제합니다.

    3. '모든 스크립트 오류에 관련된 알림 표시'를 체크합니다.

    4. 'HTTP 오류 메시지 표시'의 체크를 해제합니다.

    5. MixedModeDebug 웹 프로젝트의 Default.aspx의 body 태그에 테스트를 위해 다음과 같은 JavaScript 코드를 추가합니다.
    JavaScript
    <script type="text/javascript">
        var today = Date();
        alert(today.toString());
    </script>

    6. 솔루션 익스플로러의 MixedModeDebug 웹 프로젝트에서 마우스 오른쪽 버튼을 누르고 Properties를 선택하거나 Properties 항목을 더블 클릭합니다.

    7. Web 탭의 Debuggers 섹션에서 Silverlight의 체크를 해제합니다.
    사용자 삽입 이미지


    8. 속성 패널을 닫고 5번 과정에서 추가한 JavaScript 코드에 브레이크 포인트를 추가합니다.

    9. 솔루션을 빌드하고 F5를 눌러 디버깅 모드로 실행합니다.

    10. 다음과 같이 JavaScript에서 브레이크가 걸리고 줄 단위 혹은 코드 단위 진행이 가능합니다.

    여기까지 작성된 프로젝트를 첨부합니다.
    MixedModeDebug.zip

    MixedMode 디버깅과 JavaScript 디버깅



    IIS를 사용한 디버깅

    기본적으로 ASP.NET 페이지 프로젝트는 Visual Studio의 가상 웹서버를 통해 호스팅됩니다. 실제 프로젝트에서는 IIS와 연동을 통한 테스트를 직접 수행할 수 있습니다.
    Howto:4-8 IIS를 사용한 디버깅
    1. MixedModeDebug 웹 프로젝트에서 마우스 오른쪽 버튼을 누르고 Properties를 선택하거나 Properties 항목을 더블 클릭합니다.

    2. Web 탭의 Servers 섹션에서 Use IIS Server를 체크합니다. 이 옵션은 반드시 IIS 서버가 사용 가능한 상태여야 합니다.

    3. Create New Virtual Directory를 클릭하고 새로 생성할 디렉토리의 정보를 입력합니다.

    4. 속성 패널을 닫고 모두 저장합니다.
    이제 실제 IIS 서버를 사용하여 디버깅을 할 수 있습니다.

    참고

    Silverlight 공식 QuickStarts 참고:
    http://silverlight.net/QuickStarts/Start/Debug.aspx

    Visual Studio 디버깅 참고:
    http://msdn2.microsoft.com/ko-kr/library/sc65sadd(VS.80).aspx
    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    매니지드 코드의 기초
    준비 사항
    Silverlight 개발의 기초에서 개발에 필요한 도구와 기술에 대해 설명하고 있습니다.
    이벤트 핸들링에서 개체의 이벤트를 처리하는 방법에 대해 설명하고 있습니다.

    Silverlight 프로그래밍 모델

    프로그래밍 모델 소개
    Silverlight 프로그래밍은 크게 Silverlight 1.0 Beta로 릴리즈되어 JavaScript를 사용하는 언매니지드 코드 API와 Silverlight 1.1 Alpha로 릴리즈되어 C#또는 VB.NET을 사용하는 매니지드 코드 API를 사용하는 모델로 구분할 수 있습니다. 1.1 Alpha 릴리즈에서는 DLR(Dynamic Language Runtime)을 통해 파이선이나 JScript를 사용할 수도 있습니다.

    어느쪽이든 Silverlight 컨트롤(또는 페이지)는 HTML 파일 안에 호스팅되는 웹 애플리케이션으로써 JavaScript를 통해 초기화되고 HTML 페이지에 로드되며 이에 따라 매니지드 코드와 언매니지드 코드를 섞어서 사용할 수도 있습니다.

    현재 1.1 Alpha에 대한 정확한 문서화는 이루어져있지 않지만 대다수의 API 모델과 사용 방법이 1.0 Beta의 그것과 동일합니다. Silverlight 1.1 Alpha에서의 매니지드 코드 작성은 VS의 IDE에서 제공하는 인텔리센스, 코드 자동완성 기능과 개체 브라우저를 활용하여 직관적인 코드 작성이 가능하며, 개체의 구체적인 기능과 사용 방법은 1.0 Beta의 레퍼런스를 참고할 수 있겠습니다.

    이 글에서는 직접적인 사용 방법 보다는 Silverlight 프로그래밍에 빈번히 사용되는 기초적인 개체의 기초적인 사항과 기반 지식을 간략하게 소개합니다. Silverlight 1.1 Alpha API는 성능이나 기능 개선 등의 이유로 언제든지 변경될 수 있으니 세부적인 사항은 항상 MSDN을 참고하시기 바랍니다.

    매니지드 클래스 계층 구조
    Silverlight의 컨트롤과 UI 기능을 제공하는 많은 클래스는 기본적으로 다음과 같은 계층 구조로 이루어집니다.


    WPF 프로그래밍을 해보셨다면 WPF의 엘리먼트 계층 구조와 유사하다는 것을 알 수 있을 것입니다. 실제로 몇 가지 기능적인 제약을 제외하고는 기본적인 계층 구조의 각 클래스의 역할이 WPF와 같습니다. Silverlight에서는 FrameworkElement를 상속받는 클래스를 일반적인 엘리먼트 클래스라고 생각할 수 있고 이것은 UI를 구성하는데 기본적으로 필요한 유용한 속성과 메서드 및 이벤트를 제공하며 XAML 마크업에서 UI의 한 부분으로 선언할 수 있습니다.

    하지만 XAML에서 사용하는 모든 요소가 FrameworkElement는 아닙니다. 특수한 UI 컴포넌트나 이벤트를 처리하기 위한 컨트롤들은 그들만의 고유한 속성을 가지고 있습니다. 예를 들어 Animation이나 Storyboard에서 파생되는 클래스들이 있는데, 이들은 UI 엘리먼트의 타겟 속성으로 사용될 것입니다.

    개체 트리와 개체 찾기
    이 절에 대한 내용은 앞서 포스팅한 이벤트 핸들링에서 자세히 설명하고 있습니다. 여기에서는 간략하게 요약하겠습니다.

    Silverlight에서 UI 구성은 XAML 마크업을 통한 계층 구조로 이루어지며 마크업의 루트 엘리먼트는 x:Class를 정의하고 여기에서 정의된 클래스가 코드-비하인드에서 매니지드 코드를 사용하여 제어할 수 있게 됩니다.

    이 때문에 코드-비하인드내에 정의된 같은 이름의 클래스에서 this 키워드는 마크업의 루트 엘리먼트를 의미합니다.
    마크업에서 정의된 하위 엘리먼트들을 접근하는 방법은 루트 엘리먼트가 Panel에서 파생되는 Canvas 등의 개체일 경우 Panel.Children 컬렉션을 통해 인덱스 또는 반복자를 사용하거나 코드-비하인드에서 접근할 엘리먼트에 x:Name 어트리뷰트를 지정하고 코드에서 DependencyObject.FindName 메소드를 사용하여 해당 이름으로 개체의 참조를 얻을 수 있습니다.

    각 개체들은 FrameworkElement.Parent 속성을 통해 자신의 부모 개체를 참조할 수 있으며 루트 엘리먼트에서 이 속성은 null을 가리킵니다.

    주요 개체와 속성들

    너비(Width)와 높이(Height)
    너비와 높이는 FrameworkElement가 제공하는 대표적인 UI 엘리먼트를 위한 속성입니다. FrameworkElement에서 파생된 Canvas, TextBlock 또 Shape와 같은 개체들의 너비와 높이를 이 속성으로 설정하거나 얻을 수 있습니다.

    TextBlock과 같은 어떤 엘리먼트들은 ActualWidth와 ActualHeight이라는 동적으로 계산되는 읽기 전용 속성을 제공하기도 합니다. TextBlock의 ActualWidth와 ActualHeight은 사용자가 지정한 Width와 Height에 관계없이 실제 표시될 Text에 해당하는 실제 너비와 높이를 의미합니다.

    반대로 얘기하자면 어떤 엘리먼트들은 Width와 Height의 설정이 실제로 표시되는 내용의 너비와 높이와 정확히 일치하지 않을 수도 있습니다.

    첨부된 속성(Attached Properties) 설정 및 얻기
    첨부된 속성은 심지어 코드상의 멤버 목록에 없는 속성일지라도 마크업에서 다른 속성과 같이 어트리뷰트로 정의할 수 있는 속성을 말합니다. 예를 들어, Canvas는 자신의 자식 엘리먼트들에게 그들의 레이아웃 좌표를 결정할 수 있게 하는 속성을 제공합니다. 이 속성은 Canvas.Left와 Canvas.Top 그리고 Canvas.ZIndex입니다. XAML에서 이러한 첨부된 속성을 사용하려면 반드시 그 속성의 Owner.Property와 같이 전체 경로를 지정해야 합니다.

    XAML에서는 간단하게 Owner.Property 구분으로 설정이 가능하지만 코드에서는 다른 방법을 사용해야 합니다. 왜냐하면 코드에서 Owner.Property = 값; 이런식으로는 단 하나의 개체에 대한 속성만 지정할 수 있기 때문입니다.

    매니지드 코드에서 첨부된 속성은 DependencyObject.GetValue와 SetValue로 읽고 쓸 수 있습니다. 첨부된 속성은 DependencyProperty라는 Object 형태로 표현되며 따라서 읽고 쓸 때 해당 DependencyProperty 타입과 실제 타입으로 캐스팅이 필요합니다.
    XAML 첨부된 속성 설정의 예
    <Canvas Width="500" Height=200">
        <TextBlock x:Name="myText" Canvas.Left="200", Canvas.Top="10" Text="test" />
    </Canvas>

    C# DependencyProperty를 사용하는 방법
    // 가져오기
    double currentLeft = (double) myText.GetValue(Canvas.LeftProperty);

    // 설정하기
    myText.SetValue(Canvas.LeftProperty, 100);

    DependencyProperty로 캐스팅하는 첨부된 속성의 설정과 읽기는 캐스팅 과정 때문에 성능상의 불이익이 있으므로 첨부된 속성이 아닌 일반 속성들은 GetValue나 SetValue를 사용하지 않고 해당 속성을 직접 설정하는 것이 유리합니다.

    TextBlock과 Text API
    TextBlock은 연속적인 텍스트를 표현하는데 효과적인 수단을 제공합니다. 현재는 중/동아시아 지역 언어를 제대로 표현하지 못하고 있지만 정식 버전이 나올 때에는 해결될 것입니다. 이 예제에서는 정상적으로 표현되는 영문 폰트만을 사용합니다.

    TextBlock은 단순한 한줄 짜리 텍스트에서 여러 줄에 걸친 다양한 표현까지 출력하기 위한 수단을 제공합니다.
    XAML 멀티 라인을 지원하는 TextBlock 예제
    <TextBlock FontSize="30">
        <Run FontFamily="Arial" FontSize="20" Text="Arial, first line" Foreground="red" />
        <LineBreak />
        <Run FontFamily="Comic Sans MS" Text="Comic Sans MS, second line" />
    </TextBlock>


    위의 예제에서 TextBlock은 일종의 텍스트 컨테이너 루트라고 볼 수 있고 그 안에 Run이란 엘리먼트로 독립적인 폰트 속성의 텍스트를 추가할 수 있고 LineBreak란 엘리먼트로 폰트 사이즈에 맞춰 다음 줄로 넘어갈 수 있습니다. 매니지드 코드로 위의 예제를 표현하자면 다음과 같습니다.
    C# 매니지드 코드로 작성한 TextBlock
    TextBlock tb = new TextBlock();
    tb.FontSize = 30;

    Run
    run = new Run();
    run.FontFamily = "Arial";
    run.FontSize = 20;
    run.Foreground = new SolidColorBrush(Color.FromRgb(0xFF, 0x00, 0x00));
    run.Text = "Arial, first line";
    tb.Inlines = new Inlines();
    tb.Inlines.Add(run);

    tb.Inlines.Add(
    new LineBreak());

    run =
    new Run();
    run.FontFamily = "Comic Sans MS";
    run.Text = "Comic Sans MS, second line";
    tb.Inlines.Add(run);

    XAML의 엘리먼트와 매니지드 코드의 클래스가 1:1로 매치되고 있어서 쉽게 접근할 수 있습니다. TextBlock의 상세한 속성과 기능은 MSDN을 참고하십시오.

    컬러와 브러쉬
    XAML에서 색상은 약 256가지의 일반적인 색상의 이름(Red, Blue)을 사용하거나 #를 붙인 RGB 표기 또는 ARGB 표기를 사용할 수 있습니다.
    RGB는 Red, Green, Blue 색상을 순서대로 16진수로 표현하고 ARGB는 불투명도를 의미하는 Alpha를 앞에 붙입니다.

    매니지드 코드에서 RGB 색상과 ARGB 색상은 Color.FromRGB와 Color.FromScRgb 및 Color.FromArgb 메소드를 통해 얻을 수 있습니다. 이 색상 값은 보통 어떤 컨트롤을 단일 색상 브러쉬로 칠할 때 사용됩니다. 사용 예제는 앞서 소개한 TextBlock 예제를 참고하십시오.

    브러쉬는 어떤 영역을 칠하는 방법을 나타내는 클래스로 단일 색상을 의미하는 SolidColorBrush, 직선형 그래디언트를 의미하는 LinerGradientBrush, 원형 그래디언트를 의미하는 RadialGradientBrush를 비롯해 색상이 아닌 이미지나 심지어 비디오를 소스로 사용할 수도 있습니다. 자세한 것은 역시 MSDN을 참조하십시오.

    자주 사용되는 복잡한 형태의 그래디언트나 이미지 브러쉬들을 그때그때 XAML이나 코드로 작성하여 사용한다면 유지보수가 굉장히 힘들어지고 메모리도 많이 차지하게 될 것입니다. 브러쉬 등의 개체는 build action을 embedded resource로 설정한 XAML을 사용하여 리소스의 형태로 사용할 수 있으며 이렇게 리소스화 된 개체는 다른 매니지드 코드에서 XamlReader 클래스를 사용하여 로드할 수 있습니다.

    복잡한 형태의 드로잉을 가지는 개체는 Expression Blend와 같은 디자인 툴을 사용하여 XAML로 작성하고 이것을 코드에서 로드하여 사용하는 형태가 이상적일 것입니다.

    마우스와 마우스 포인터의 위치
    Silverlight UI는 HTML 상에 하나의 컨트롤로써 로드되기 때문에 마우스 포인터의 위치를 항상 얻을 수 있는 건 아닙니다. Silverlight에서 마우스 포인터를 획득하는 것은 마우스 포인터가 루트 컨트롤의 영역 내에 있을 때만 가능하며, 마우스 포인터의 위치는 오직 마우스 관련 이벤트를 통해서만 얻을 수 있습니다.

    일반적인 마우스 관련 이벤트는 UIElement 클래스에서 제공하고 있습니다. 대표적인 마우스 이벤트인 MouseMove는 마우스 포인터가 해당 컨트롤 위에서 움직일 때 발생하며 MouseMove 이벤트 핸들러를 작성하여 마우스 포인터의 위치를 얻을 수 있습니다.
    C# 마우스 포인터의 위치 얻기
    void Page_MouseMove(object sender, MouseEventArgs e)
    {
        Point pos = e.GetPosition((UIElement)sender);
        double x = pos.X; // X 좌표
        double y = pos.Y; // Y 좌표
    }

    마우스 관련 이벤트는 보통 MouseEventArgs 클래스를 통해 전달됩니다. Silverlight는 마우스 포인터의 위치를 직접 X, Y로 전달하는 대신 GetPosition 메소드를 통해 X, Y 좌표를 나타내는 Point 개체를 획득하도록 되어 있습니다.

    약간 번거러워 보이는 이 메소드는 대신 인수로 좌표의 기준이 되는 UIElement의 참조를 전달할 수 있으며 null을 전달할 경우 Silverlight 컨트롤 전체에서의 좌표를 반환합니다. 심지어 이벤트와 관계 없는 다른 UIElement의 참조를 전달하여 해당 엘리먼트로부터의 좌표를 구할 수도 있지만 보통은 이벤트가 일어난 개체를 기준으로 할 것이며 이 때 이벤트가 발생한 개체를 의미하는 sender 개체를 UIElement로 캐스팅하여 전달하면 됩니다.

    현재 Silverlight는 윈도우즈뿐만 아니라 MAC도 고려하는 크로스 플랫폼으로 개발되고 있기 때문에 윈도우즈 UI 프로그래밍에서 당연하다고 생각되는 몇 가지 속성이나 이벤트가 빠져 있습니다. 예를 들어 마우스 오른쪽 버튼과 휠 버튼이라던가 Alt 키가 눌렸는지 여부 등 윈도우즈에서는 여러모로 유용한 정보들이 있습니다.

    이것은 기술적인 문제보다는 정책적인 문제가 고려되는 사항으로 앞으로의 지원 계획이 정확히 어떻게 될지는 확실하지 않습니다.

    XamlReader 클래스와 스트림
    JavaScript에서는 생성자가 없어서 엘리먼트의 새 인스턴스를 생성하여 개체 트리에 추가할 수 없습니다. 그래서 동적으로 표현할 UI 요소들을 DHTML 기법에서 그랬던 것처럼 숨겨진 엘리먼트를 미리 만들어두고 시나리오에 따라 보여주거나 움직이는 방법을 사용했습니다. 또는 Control.content.createFromXAML 메소드를 이용하여 문자열로부터 엘리먼트를 동적으로 생성하여 개체 트리에 추가하는 방법을 사용하기도 했습니다.

    매니지드 코드에서는 개체를 선언하는 것으로 생성자에 접근할 수 있습니다. 때문에 대부분의 경우 XamlReader.Load(createFromXAML과 같은 역할을 하는 메소드) 메소드로 XAML 텍스트를 직접 코드로 로드하는 것은 불필요합니다. 왜냐면 매니지드 코드는 개체 모델에서 새로운 개체를 생성하는 것이 전혀 어렵지 않기 때문입니다.

    더 구체적으로 디자인이 동적으로 복잡하게 변경될 수 있는 경우를 생각해 볼 수 있습니다. 분명히 코드에서 개체를 생성하는 것 자체는 어렵지 않지만 복잡한 디자인을 그때그때 코드로 작성한다는 것은 굉장한 낭비입니다. 이런 경우 앞서 얘기한 리소스의 경우처럼 디자이너가 필요한 UI 디자인이나 컨셉을 XAML로 작성하고 개발자는 코드에서 그 XAML 파일을 동적으로 로드하여 시나리오에 맞춰 보여주는 게 더 유리합니다. 그러면 디자이너와 개발자가 서로 격리되어 작업이 가능하며 디자이너와 개발자는 서로 정해진 네임스페이스와 개체 이름만을 공유하여 결과물인 XAML 파일만 다시 로드하면 될 것입니다.

    이러한 동작은 System.IO.StreamReader를 사용하여 효율적으로 구현할 수 있습니다. StreamReader는 여러가지 상황에 맞춰 다양한 생성자를 오버로딩하고 있으며 크게 다른 Stream 개체에서 초기화하는 방법과 파일로부터 초기화하는 방법이 있습니다.

    어떤 리소스를 XAML파일로부터 동적으로 로드하고 싶다면 두 가지 상황을 고려할 수 있습니다.
    하나는 완성된 XAML이 정적일 경우 프로젝트의 embedded resource로 추가하여 어셈블리 안에 리소스로 함께 컴파일 되도록 하고 Assembly.GetManifestResourceStream 메소드를 통해 리소스의 스트림을 획득하는 방법이 있고 다른 하나는 XAML 파일이 런타임에 동적으로 변경되는 경우 StreamReader 클래스를 생성할 때 해당 XAML의 위치를 직접 지정해주는 방법입니다.

    전자의 경우 XAML 파일의 경로는 반드시 네임스페이스를 포함한 전체 경로를 지정해야 하며, 후자의 경우 해당 XAML파일의 존재 여부를 런타임에 보장할 수 없으므로 반드시 예외 처리가 필요할 것입니다.
    C# 동적으로 XAML을 로드하는 방법
    // embedded resource로 추가된 XAML에서 스트림을 얻고 로드하는 방법
    Stream s = this.GetType().Assembly.GetManifestResourceStream("TestProejct.test.xaml");
    StreamReader sr = new StreamReader(s);
    Brush dynamicBrush = XamlReader.Load(sr.ReadToEnd());
    sr.Close();
    s.Close();

    // XAML 파일에서 직접 스트림을 얻고 로드하는 방법
    StreamReader sr = new StreamReader("/Resources/test.xaml");
    Brush dynamicBrush = XamlReader.Load(sr.ReadToEnd());
    sr.Close();

    Downloader 클래스
    Silverlight는 웹 애플리케이션입니다. 보통은 웹 서버에서 호스팅되며 따라서 모든 컨텐츠는 일단 웹 서버에 존재하게 됩니다.
    코드에서 동적으로 이런 컨텐츠를 접근하려고 하면 HTTP특성상 접근하는데 시간도 걸리고 서버도 부하가 늘어나게 될 것입니다. 빠른 반응과 효율적인 서버 운영을 위해서는 어떤 페이지에서 필요한 리소스들은 가급적 한번에 다운로드하고 같은 컨텐츠를 불필요하게 다시 요청하지 않는 게 좋을 것입니다.

    Downloader 클래스는 서버에 있는 컨텐츠를 현재 실행중인 클라이언트로 다운로드할 수 있게 해줍니다. 이렇게 다운로드 받은 컨텐츠들은 Downloader 클래스의 지원 메소드들을 통해 스트림으로 얻거나 폰트 소스 설정 등으로 활용됩니다.

    Downloader는 일반적으로 새 인스턴스를 생성한 후 DownloadProgressChanged, DownloadFailed, Completed 이벤트 핸들러를 추가한 후 Open 메소드로 읽어올 파일의 URI를 지정하고 Send 메소드를 호출하여 다운로드를 시작합니다. 만약 URI 지정이 잘못되었거나 문제가 있을 경우 DownloadFailed 이벤트가 발생하며 다운로드가 시작되면 진행 상황을 DownloadProgressChanged 이벤트를 통해 알 수 있고 다운로드가 완료되면 Completed 이벤트가 발생합니다.

    아직 Downloader 클래스의 구체적인 활용 방법은 문서화되어 있지 않습니다. 현재 시점에서 가장 많이 활용되는 것은 TextBlock에 표시할 폰트를 다운로드 받고 변경하는 코드이며 자세한 활용 방법은 MSDN을 참고하십시오.
    C# Downloader 사용 예제
    public void Page_Loaded(object o, EventArgs e)
    {
        // ... 생략 ...
        Downloader dn = new Downloader();
        dn.Completed += new EventHandler(dn_Completed);
        dn.DownloadFailed += new ErrorEventHandler(dn_DownloadFailed);
        dn.DownloadProgressChanged += new EventHandler(dn_DownloadProgressChanged);
    }

    void dn_DownloadProgressChanged(object sender, EventArgs e)
    {
        // 다운로드 진행률 얻기
        double progressPercent = ((Downloader)sender).DownloadProgress * 100;
    }

    void dn_DownloadFailed(object sender, ErrorEventArgs e)
    {
        // 다운로드 실패
    }

    void dn_Completed(object sender, EventArgs e)
    {
        // 다운로드 완료
    }

    호스팅 브라우저에서 이벤트와 정보 얻기
    Silverlight 컨트롤은 자신을 호스팅하는 HTML DOM에 접근할 수 있고 이를 통해 HTML 엘리먼트의 이벤트나 속성을 Silverlight 컨트롤의 코드에서 컨트롤 할 수 있습니다. 하지만 이런 방법으로 호스트 브라우저의 크기나 이벤트를 얻기는 상당히 어렵고 번거롭습니다.

    BrowserHost 클래스는 호스트 브라우저에 대한 실제 크기 및 풀 스크린 모드 여부를 제공하는 편리한 이벤트와 속성을 제공하며 화면을 꽉 채우거나 풀 스크린을 사용하는 Silverlight 컨트롤에서 특히 유용하게 쓸 수 있습니다.  BrowserHost 클래스를 사용하려면 System.Windows.Interop 네임스페이스를 추가해야 합니다.
    C# BrowserHost 클래스 사용 예제
    public void Page_Loaded(object o, EventArgs e)
    {
        // ...생략...
        BrowserHost.Resize += new EventHandler(BrowserHost_Resize);
        BrowserHost.FullScreenChange += new EventHandler(BrowserHost_FullScreenChange);
    }

    void BrowserHost_Resize(object sender, EventArgs e)
    {
        // 호스트 브라우저의 크기가 변경되었을 때 이벤트와 실제 크기 얻기
        double hostWidth = BrowserHost.ActualWidth;
        double hostHeight = BrowserHost.ActualHeight;
    }

    void BrowserHost_FullScreenChange(object sender, EventArgs e)
    {
        // 호스트 브라우저의 풀스크린 모드 변경과 상태 얻기
        bool hostFullScreen = BrowserHost.IsFullScreen;
    }

    호스트 브라우저의 HTML DOM에 직접 접근하는 것은 System.Windows.Browser 네임스페이스와 그 하위 클래스들로부터 지원됩니다. 자세한 사항은 다른 글에서 자세히 다룰 것입니다.

    참고

    Silverlight 공식 QuickStarts 참고:
    http://silverlight.net/QuickStarts/BuildUi/CallJavascript.aspx

    Posted by gongdo

    Silverlight 커스텀 컨트롤을 하나 만들어봤습니다.
    Silverlight이 현재는 기본으로 제공되는 컨트롤이 몇 개 없어서 단순한 버튼 조차 만들어 써야 하는데요, 내친김에 VISTA의 글래스 스타일로 만들었어요.
    디자인 감각은 꽝이라 비슷하게 만들었는지 어쨌는지 모르겠네요. =ㅅ=

    (여기에서 테스트 가능 : http://gongdo.oranc.co.kr/Silverlight/Samples/GlassButton/)

    사용자 삽입 이미지

    연습 삼아 만들어본거라 문서화는 제대로 하지 않았지만 코드 안에다가 주석은 충분히 달았으니 관심 있으신 분은 한번 소스를 받아보세요.
    GlassButton.zip

    GlassButton 샘플


    간단하게 컨트롤에 대해 요약할께요.
    Namespace : Gongdosoft.Silverlight.UX
    Class Name : GlassButton
    Properties :
    • Width : 버튼 전체의 너비
    • Height : 버튼 전체의 높이
    • Radius : 버튼의 둥글기 정도(픽셀 단위, 네 모서리에 적용)
    • Background : 배경색상 브러쉬
    • Foreground : 전경색상 브러쉬
    • LightColor : 마우스를 올렸을 때 표시될 색상값
    • ShadowMask : 버튼을 클릭했을 때 버튼을 마스킹하는 브러쉬
    • Opacity : 버튼 전체의 불투명도(0~1)
    • OpacityMask : 버튼 전체의 불투명도 마스크 브러쉬
    • BackgroundOpacity : 버튼 배경색상의 불투명도
    • Caption : 버튼의 캡션(문자열)
    • CaptionHorizontalAlign : 캡션의 수평 정렬
    • CaptionVerticalAlign : 캡션의 수직 정렬
    • FontUri : 다운로드할 폰트 또는 폰트가 들어있는 Zip의 경로를 설정
    • FontFamily : 사용할 폰트 종류(현재 한글은 Arial Unicode MS만 사용가능)
    • FontSize : 폰트의 크기(픽셀 단위)
    • FontStyle : 폰트의 스타일(이탤릭)
    • FontWeight : 폰트의 두께
    • TextDecoration : 폰트의 꾸밈(밑줄)
    • TextWrapping : 줄바꿈 속성(현재는 제대로 동작하지 않음)
    Events :
    • DownloadCompleted : FontUri에서 설정한 폰트를 다운로드 완료했을 때
    • DownloadFailed : FontUri에서 설정한 폰트를 다운로드 실패했을 때
    • DownloadProgress : FontUri에서 설정한 폰트를 다운로드 하는 진행 과정
    • Clicked : 버튼을 클릭했을 때

    나름대로 생각은 많이 했는데 제일 걸리는 부분은 한글 문제에요.
    내부적으로 Glyphs가 아닌 TextBlock을 사용했는데요 때문에 현재 사용할 수 있는 폰트는 Arial Unicode MS 폰트밖에 없어요.
    그 외의 폰트라면 영문은 제대로 표시되니까 FontUri에 폰트 파일의 경로를 설정하고 FontFamily에 폰트 이름을 설정하면 작동할거에요.

    그 외에 몇가지 속성은 XAML에서 설정할 수 없는 문제가 있는데 이건 아무래도 Silverlight의 미완료된 부분인 것 같아서 좀 더 알아봐야 할 것 같네요.

    사용기나 버그 리포트 대환영입니다. :)

    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    커스텀 컨트롤
    준비 사항
    Silverlight 개발의 기초에서 개발에 필요한 도구와 기술에 대해 설명하고 있습니다.
    이벤트 핸들링에서 개체의 이벤트를 처리하는 방법에 대해 설명하고 있습니다.

    커스텀 컨트롤 만들기

    컨트롤의 기본 구성
    Silverlight에서 컨트롤은 UI를 구성하는 XAML 마크업과 개체 모델을 구성하는 코드-비하인드로 구분할 수 있습니다. 특히 Silverlight와 같이 풍부한 사용자 인터페이스가 강조되는 프로그래밍에서 UI의 미려함은 매우 중요하므로 디자이너는 미적 감각을 충분히 살려 디자인된 컨트롤을 마크업으로 전달하고 개발자는 코드-비하인드에서 컨트롤을 모델링하고 제어하여 다른 XAML 페이지에서 재사용할 수 있습니다.

    이렇게 작성된 XAML과 코드는 하나의 라이브러리 파일(.dll)로 컴파일 되며 다른 프로젝트에서는 이 라이브러리 파일의 어셈블리를 참조하여 사용이 가능합니다.

    여기에서는 커스텀 컨트롤의 개요를 살펴보기 위해 MyButton이라는 간단한 버튼을 만들어보겠습니다.
    이 버튼은 아주 단순하게 캡션과 너비 및 높이 속성을 가지며 클릭 이벤트를 노출하여 버튼이 클릭되었을 때 핸들링 할 수 있도록 할 것입니다. 또한 속성을 변경하면 캡션이 현재 너비 및 높이의 한 가운데에 표시될 수 있도록 하겠습니다.

    Silverlight 컨트롤 프로젝트 만들기
    기본적으로 커스텀 컨트롤은 XAML이나 코드를 포함하지 않는 라이브러리의 형태로 배포될 것입니다. 때문에 Silverlight 컨트롤은 일반적으로 Silverlight 클래스 라이브러리 프로젝트를 기반으로 작성합니다.

    Howto:3-1 Silverlight 컨트롤 작성을 위한 클래스 라이브러리 프로젝트 만들기
    1. Visual Studio를 실행하고 메뉴에서 File->New->Project를 선택하거나 Ctrl+Shift+N를 눌러 새 프로젝트를 선택합니다.
    2. 새 프로젝트 다이얼로그 박스에서 Project types를 Visual C#->Silverlight로 선택하고 Templates에서 Silverlight Class Library를 선택한 후 프로젝트 이름을 MyButton이라고 입력하고 [OK]를 누릅니다.
    사용자 삽입 이미지

    3. 기본으로 생성되어 있는 Class1.cs는 필요 없으므로 솔루션 익스플로러에서 Class1.cs를 선택하고 마우스 오른쪽 버튼을 누른 후 Delete를 선택하여 삭제합니다.
    4. 메뉴에서 Project->Add New Item을 선택하거나 Ctrl+Shift+A를 눌러 새 아이템을 선택합니다.
    5. 새 아이템 다이얼로그 박스에서 Silverlight User Control을 선택하고 클래스 이름을 MyButton이라고 입력하고 [OK]를 누릅니다.
    사용자 삽입 이미지

    노트
    다시 설명하겠지만, Silverlight User Control은 하나의 라이브러리 파일로 배포하기 위해 XAML파일의 build action 속성을 embedded resource 형태로 설정하며 따라서 컴파일시 XAML 파일은 어셈블리에 포함되게 됩니다.


    UI 디자인하기
    실제 작성해야 할 컨트롤은 미려한 디자인과 기능성 그리고 인터페이스 접근성을 고려해야 할 것입니다. 그러기 위해 UI의 디자인은 Expression Blend나 Design 등 XAML 코드를 작성할 수 있는 디자인 툴을 사용하는 것이 좋습니다.

    여기에서는 단순히 TextBlock을 하나 만드는 걸로 만족하겠습니다.
    Howto:3-2 XAML로 기본적인 UI 디자인 하기
    1. MyButton.xaml을 열고 다음 코드를 루트 Canvas 엘리먼트 안에 넣습니다.
    XAML
    <TextBlock x:Name="text"></TextBlock>

    2. 이 TextBlock은 버튼의 캡션을 표시하는 역할을 수행할 것입니다.
    코드에서 제어할 필요가 있는 UI 요소는 반드시 x:Name으로 이름을 지정하여 코드에서 참조할 수 있도록 해야 합니다.

    개체 참조 얻기
    디자인이 완료되었으면 코드-비하인드에서는 UI 모델을 구현하기 위해 제어할 UI 개체의 참조를 획득해야 합니다.
    MyButton.xaml.cs를 보면 다음과 같이 Control 클래스를 상속하며 기본 생성자가 미리 만들어져 있음을 확인할 수 있습니다.
    C# 기본 생성자
    namespace MyButton
    {
        public class MyButton : Control
        {
            public MyButton()
            {

                System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("MyButton.MyButton.xaml");
                this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());
            }
        }
    }

    이 코드는 MyButton 클래스의 어셈블리로부터 XAML 파일을 리소스 스트림으로 읽어와서 그 스트림으로부터 초기화를 수행합니다. 이를 위해 MyButton.xaml 파일의 속성을 보면 build action이 embedded resource로 설정되어 있을 것입니다.

    이 특수한 형태의 초기화는 Control 클래스의 InitializeFromXaml 메소드를 통해 구현됩니다.

    미리 생성된 코드에서 InitializeFromXaml 메소드를 호출만 하지만 이 메소드는 XAML 스트림을 읽어서 초기화한 후 이 XAML의 루트 개체에 대한 참조를 반환합니다. 이 참조를 클래스의 지역 변수로 저장하여 UI 개체를 코드로 제어할 수 있습니다.

    또한 루트 개체에 대한 참조를 얻으면 XAML에서 x:Name을 지정한 개체에 대한 참조를 FindName 메소드를 사용하여 얻을 수 있고 이런 식으로 XAML내의 모든 개체를 코드에서 제어할 수 있습니다.
    Howto:3-3 XAML에서 디자인된 개체의 참조를 얻기
    1. MyButton.xaml.cs를 엽니다.
    2. 클래스의 private 지역 변수로 FrameworkElement 타입의 implementationRoot를 선언하고 InitializeFromXaml의 반환값을 implementationRoot에 대입합니다.
    3. TextBlock에 대한 참조를 보유하기 위해 클래스의 private 지역 변수로 TextBlock 타입의 text를 선언하고 implementationRoot.FindName("text") 메소드를 사용하여 참조를 얻습니다. 이렇게 완성된 코드는 다음과 같습니다.

    C# 개체 참조를 보유하기 위한 코드 수정
    namespace MyButton
    {
        public class MyButton : Control
        {
            private FrameworkElement implementationRoot;
            private TextBlock text;

            public MyButton()
            {

                System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("MyButton.MyButton.xaml");
                implementationRoot =
    this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());

                text = implementationRoot.FindName("text") as TextBlock;
            }
        }
    }

    속성 및 이벤트 추가하기
    컨트롤에서 가장 중요한 것은 적절한 속성(Property)과 이벤트(Event)를 정의하는 것입니다.
    속성과 이벤트는 이 컨트롤을 사용하는 마크업에서 어트리뷰트의 형식으로 선언하고 설정할 수 있으며 이 컨트롤 개체에 대한 참조를 획득한 코드에서도 접근할 수 있습니다. 앞서 얘기한 것처럼 여기에서는 캡션(Caption), 너비(Width), 높이(Height) 속성과 Click 이벤트를 추가하도록 하겠습니다.

    Control 클래스는 FrameworkElement를 상속하고 있으며 기본적인 너비(Width), 높이(Height), 클리핑 영역(Clip), 커서(Cursor), 불투명도(Opacity) 등 많은 기본적인 속성을 그대로 받아 옵니다. 따라서 우리가 추가하려는 속성인 너비와 높이는 FrameworkElement에서 이미 선언이 되어 있으며 이 속성은 virtual이 아니므로 오버라이딩이 불가능하고 만약 똑같이 Width라는 이름의 속성을 만든다면 컴파일러는 이 속성이 FrameworkElement.Width 속성에 의해 숨겨질 것이라는 경고를 내릴 것입니다.

    이렇게 부모 클래스에서 미리 선언된 일반적인 이름의 속성을 재정의 하고 싶을 때에는 속성의 선언에 new 키워드를 추가해야 합니다.
    Howto:3-4 속성 추가하기
    1. Width 속성을 추가합니다. Width는 implementationRoot 즉, 컨테이너 역할을 하는 루트 캔버스 개체의 너비와 싱크되며 이 값을 수정하면 텍스트의 위치를 가운데 정렬하기 위해 레이아웃 계산을 다시 수행합니다. Width라는 이름은 이 컨트롤이 상속하는 FrameworkElement의 Width와 중복되어 이 속성이 숨겨지므로 new 키워드를 사용하여 재정의 하고 이 속성을 다른 클래스로 파생할 수 있도록 virtual 키워드도 추가하였습니다.
    C# Width 속성 정의(클래스에 추가할 것)
    public virtual new double Width
    {
        get { return implementationRoot.Width; }
        set
        {
            implementationRoot.Width = value;
            UpdateLayout();
        }
    }

    UpdateLayout 메소드는 텍스트의 위치를 중앙 정렬하는 기능을 수행하며 일반적으로 컨트롤의 속성이 변경되어 레이아웃이나 화면 출력을 변경할 필요가 있을 때 내부적으로 사용됩니다. UpdateLayout 메소드의 정의는 아래에 있습니다.

    2. Width와 마찬가지로 Height 속성을 추가합니다.
    C# Height 속성 정의(클래스에 추가할 것)
    public virtual new double Height
    {
        get { return implementationRoot.Height; }
        set
        {
            implementationRoot.Height= value;
            UpdateLayout();
        }
    }

    3. 텍스트 내용을 나타내는 Caption 속성을 추가합니다. Caption은 새로 정의하는 속성이므로 일반적인 속성 선언과 같이 하면 됩니다.
    C# Caption 속성 정의(클래스에 추가할 것)
    public string Caption
    {
        get { return text.Text; }
        set
        {
            text.Text = value;
            UpdateLayout();
        }
    }

    4. 속성이 변경될 때 텍스트 위치 계산을 위한 UpdateLayout 메소드를 구현합니다. UpdateLayout은 내부적으로만 사용되므로 private으로 선언합니다. TextBlock은 현재 자신의 텍스트 내용에 해당하는 너비와 높이를 반환하는 ActualWidth와 ActualHeight이라는 편리한 속성을 제공합니다.
    C# UpdateLayout 메소드 정의(클래스에 추가할 것)
    private void UpdateLayout()
    {
        text.SetValue(Canvas.LeftProperty, (implementationRoot.Width - text.ActualWidth) / 2);
        text.SetValue(Canvas.TopProperty, (implementationRoot.Height - text.ActualHeight) / 2);
    }

    이제 이벤트를 추가합니다.
    우리가 추가할 이벤트는 버튼 클릭이 완료된 시점입니다. 클릭 동작은 마우스 버튼이 눌렸다가(down) 뗀(up) 그 순간을 의미하며 이런 이벤트는 별도로 정의되어 있지 않습니다.

    주의해야 할 점은 버튼 위에서 마우스 버튼을 눌렀다가 떼지 않고 버튼 바깥으로 이동할 수도 있다는 겁니다. 따라서 클릭 이벤트를 구현하기 위해서는 마우스 버튼이 눌린 상태를 기억하는 변수를 하나 만들고 버튼 바깥으로 마우스가 나간 경우 그 상태를 클리어 해줄 필요가 있습니다.
    Howto:3-5 이벤트 핸들링 및 외부로 노출할 이벤트 정의
    1. 마우스의 눌린 상태를 기억하기 위한 멤버 변수를 클래스의 private으로 선언합니다.
    C# 마우스 버튼 상태 멤버 변수 추가(클래스에 추가할 것)
    private bool mouseDowned;

    2. 외부로 노출할 이벤트를 선언합니다. 이벤트는 delegate를 정의하여 전달할 파라미터의 타입을 명시해야 하는데 우리가 추가할 Click 이벤트는 특별히 전달해야 할 파라미터가 없으므로 미리 선언된 delegate인 EventHandler를 사용하면 됩니다. 클래스에 다음의 이벤트 선언을 추가합니다. 만약 사용자가 특정한 파라미터를 전달하고 싶다면 EventArgs 클래스를 상속하는 파라미터 전달용 클래스를 정의하고 delegate를 따로 선언해야 합니다.
     
    C# 이벤트 선언 추가(클래스에 추가할 것)
    public event EventHandler Clicked;

    3. 루트 개체의 마우스 이벤트를 처리할 이벤트 핸들러를 추가합니다. 여기에서 필요한 이벤트는 MouseLeftButtonDown, MouseLeftButtonUp 그리고 MouseLeave 입니다. MyButton 생성자 코드에 다음 코드를 추가합니다.
    C# 이벤트 핸들러 추가(생성자에 추가할 것)
    implementationRoot.MouseLeftButtonDown += new MouseEventHandler(implementationRoot_MouseLeftButtonDown);
    implementationRoot.MouseLeftButtonUp += new MouseEventHandler(implementationRoot_MouseLeftButtonUp);
    implementationRoot.MouseLeave += new EventHandler(implementationRoot_MouseLeave);

    기본적으로 이벤트 핸들러는 코드 자동완성 기능을 사용하는게 편리합니다. 예를 들어 MouseLeftButtonDown 이벤트는 MouseLeftButtonDown += 까지 입력하고 탭을 두번 누르면 골격 코드가 자동으로 생성됩니다.

    4. 자동으로 생성된 코드를 수정하여 마우스 버튼이 눌렸을 때 mouseDowned를 true로 설정하고 마우스 버튼이 들렸을 때 mouseDowned가 true일 경우 Clicked 이벤트를 발생시키고 마우스 커서가 빠져나갔을 때 mouseDowned를 false로 설정합니다.
    C# 이벤트 핸들러 구현
    void implementationRoot_MouseLeftButtonDown(object sender, MouseEventArgs e)
    {
        mouseDowned = true;
    }

    void implementationRoot_MouseLeftButtonUp(object sender, MouseEventArgs e)
    {
        if (mouseDowned == true && Clicked != null)
        {
            Clicked(this, null);
            mouseDowned = false;
        }
    }

    void implementationRoot_MouseLeave(object sender, EventArgs e)
    {
        mouseDowned = false;
    }

    주의할 점은 Clicked 이벤트가 null인지 여부를 반드시 확인해야 합니다. 또 여기서 Clicked 이벤트의 EventArgs를 null로 전달하였기 때문에 사용하는 쪽에서 이 파라미터를 null 체크 없이 접근할 경우 억세스 위반이 일어날 것입니다.

    여기까지 작성된 소스코드 및 프로젝트를 첨부하였습니다. 직접 작성한 것과 비교해보세요 :)
    MyButton1.zip

    첫번째 예제



    컨트롤 테스트 하기

    테스트를 위한 Silverlight 페이지 프로젝트 추가
    작성된 컨트롤은 라이브러리일 뿐 실제 UI가 아닙니다. 이 컨트롤을 테스트하려면 실제로 이 컨트롤을 Silverlight 페이지에 로드하여 표시해야 합니다.

    Howto:3-6 테스트 프로젝트 추가하기
    1. MyButton 프로젝트를 그대로 열어놓은 상태에서 메뉴의 File->Add->New Project를 선택하고 Silverlight Project 템플릿을 선택한 후 이름을 MyButtonTester라고 설정하고 [OK]를 누릅니다. 솔루션 익스플로러에서 다음과 같은 모습을 확인할 수 있습니다.


    2. 메뉴의 Project->Add Reference를 선택하거나 솔루션 익스플로러에서 MyButtonTester 프로젝트의 Reference 항목에서 마우스 오른쪽 버튼을 클릭한 후 Add Reference를 선택합니다. 참조 추가 창에서 [Project] 탭을 보면 작성된 MyButton 프로젝트 항목이 있을 것입니다. MyButton을 선택하고 [OK]를 누릅니다.


    3. 솔루션 익스플로러의 MyButtonTester 프로젝트에서 마우스 오른쪽 버튼을 클릭한 후 Set as Startup Project를 선택하고 TestPage.html에서 마우스 오른쪽 버튼을 클릭한 후 Set as Startup Page를 선택하여 테스트 프로젝트로 디버깅 할 수 있게 합니다.

    4. 테스트할 페이지 즉, Page.xaml의 루트 엘리먼트에 사용할 컨트롤의 네임스페이스를 선언하고 어셈블리를 지정합니다.
    XAML 네임스페이스 선언 및 어셈블리 지정
    <Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="MyButtonTester.Page;assembly=ClientBin/MyButtonTester.dll"
        xmlns:my="clr-namespace:MyButton;assembly=ClientBin/MyButton.dll"
        Width="640"
        Height="480"
        Background="White">
    </Canvas>

    외부 라이브러리를 사용할 때에는 위와 같이 루트 엘리먼트에서 "xmlns:이름" 구문으로 네임스페이스를 지정하고 clr-namespace를 "컨트롤의 네임스페이스명" 으로 지정하며 assembly를 라이브러리 파일(.dll)의 경로로 지정해주면 됩니다.

    5. 루트 캔버스에 컨트롤을 추가합니다.
    XAML 컨트롤 추가
    <Canvas ... 생략 ...>
        <my:MyButton x:Name="testButton" Width="100" Height="50" Caption="button test" />

    </Canvas>

    6. 파일을 저장하고 Clicked 이벤트를 처리하기 위해 코드-비하인드에 Clicked 이벤트 핸들러를 추가합니다. 앞서서 x:Name으로 testButton을 지정했으므로 코드-비하인드에서는 자동 생성된 코드에 의해 같은 이름으로 개체를 참조할 수 있습니다.
    C# MyButton의 Clicked 이벤트 핸들러 추가
    public void Page_Loaded(object o, EventArgs e)
    {
        // Required to initialize variables
        InitializeComponent();
        testButton.Clicked += new EventHandler(testButton_Clicked);
    }

    void testButton_Clicked(object sender, EventArgs e)
    {
        testButton.Caption = "Clicked!";
    }

    7. F6을 눌러 빌드하고 F5를 눌러 디버그 모드로 실행하여 클릭했을 때 글자가 바뀌는지 확인합니다.


    여기까지 진행해보면 분명히 클릭 이벤트는 잘 작동하지만 우리가 의도한대로 텍스트가 버튼의 한가운데로 정렬되지 않았음을 알 수 있습니다. 왜냐하면 마크업에서 MyButton의 어트리뷰트에 Width=100 Height=50을 지정하였는데 이대로라면 텍스트가 해당 위치를 벗어나지 않는 다는 것을 의미합니다. 그런데 출력된 텍스트는 한참 멀리 떨어져 있고 자세히 보면 640, 480의 한가운데로 정렬되어 있음을 알 수 있습니다.

    이 문제는 Silverlight의 버그인지 사용 방법상의 차이인지 확실치 않습니다만 다음 절에서 얘기할 약간의 추가 작업을 통해 수정할 수 있습니다.
    우선 여기까지의 프로젝트를 첨부하였습니다.
    MyButton2.zip

    두번째 예제



    특수한 문제점과 해결

    Silverlight 페이지 즉, MyButtonTester에서 MyButton을 사용할 때의 모습을 간략하게 도식화하면 다음과 같습니다.


    MyButtonTester의 XAML코드에서 MyButton을 하나 선언하였고 여기에서 Width, Height, Caption속성을 설정(set)하였습니다. 따라서 이 프로젝트를 디버깅 모드로 실행했을 때 MyButton의 Width, Height, Caption 속성의 'set' 부분의 코드가 실행될 것을 기대할 수 있습니다.
    MyButton.xaml.cs에서 Width, Height, Caption 속성의 'set' 코드에 F9를 눌러 브레이크 포인트를 각각 설정하고 F5를 눌러 디버깅 모드로 실행해보시기 바랍니다.

    이상하게도 Caption 속성에는 브레이크가 걸리지만 Width와 Height에는 걸리지 않는 걸 확인할 수 있습니다.
    혹시 Width와 Height이 정상적으로 작동하지 않은지 확인하기 위해 MyButtonTester의 코드-비하인드에서 코드로 직접 Width와 Height을 설정해보면 그 코드에 대해서는 브레이크가 작동하며 코드 자체는 정상적이라는 걸 알 수 있습니다.

    이 문제는 Control에서 상속받은 모든 기본 속성에서 공통적으로 나타납니다. 따라서 Control 및 그 상위 클래스들에서 상속받는 속성과 같은 이름의 속성을 재정의했을 때에는 이들 속성에 대한 초기화를 별도로 해줄 필요가 있습니다.

    Howto:3-7 상위 클래스에서 상속받은 속성과 같은 이름을 가지는 속성을 재정의 할 때의 추가 작업
    1. MyButton 클래스의 생성자에 컨트롤이 로드 완료되었을 때 처리할 이벤트 핸들러를 추가합니다. 마찬가지로 코드 자동 생성기능을 활용합니다.
    C# 컨트롤 로드 완료시 처리 이벤트 핸들러 추가
    public MyButton()
    {
        // ... 생략
        implementationRoot.Loaded += new EventHandler(implementationRoot_Loaded);
    }

    2. 추가된 이벤트 핸들러에서 상위 클래스(base)와 중복되는 이름의 속성을 하나씩 가져옵니다.
    C# 이벤트 핸들러 작성
    // 클라이언트 측에서 이 컨트롤의 로드를 완료하였을 때 처리
    void implementationRoot_Loaded(object sender, EventArgs e)
    {
        // 로드가 완료되었을 때 상위 클래스의 속성으로부터 미완료된 속성을 수작업으로 설정해야 함
        implementationRoot.Width = base.Width;
        implementationRoot.Height = base.Height;
        UpdateLayout();
    }

    3. F6을 눌러 빌드하고 F5를 눌러 다시 실행하여 정상적으로 Width와 Height 속성이 적용되었는지 확인합니다.

    여기까지 완성된 프로젝트입니다.
    MyButton3.zip

    완성된 컨트롤 프로젝트


    이 외에도 커스텀으로 작성한 컨트롤을 올린 페이지는 Expression Blend를 사용할 수 없게 되며 VS의 IDE에서도 XAML 코드의 인텔리센스를 지원하지 않는 등 외부적인 문제도 아직 남아있습니다. 하지만 이 문제는 아마도 정식판이 나오면서 해결되지 않을까 기대를 해봅니다.

    참고

    Silverlight 공식 QuickStarts 참고:
    http://silverlight.net/QuickStarts/BuildUi/CustomControl.aspx

    Silverlight 샘플 컨트롤 참고: Silverlight 1.1 SDK에서 SilverlightControls 폴더를 참고합니다.

    개발자들이 공개하는 커스텀 컨트롤:
    http://blogs.msdn.com/devdave/archive/2007/05/17/silverlight-1-1-alpha-layout-system-and-controls-framework.aspx (Grid, StackPanel 등의 컨테이너 샘플)
    Posted by gongdo
    http://uxkorea.net/blog_post_62.aspx 이 글과 http://9eye.net/222 이 글에서 Glyphs를 활용한 한글 표시 기법에 대해서 알 수 있었고, http://gongdo.tistory.com/88 여기에서 TextBlock에서 사용가능한 한글에 대해 알아봤습니다.

    어느 방법이든 현재로선 추가작업이 비교적 많이 필요하고 어차피 정식판이 나올때 즈음에선 수정이 안될래야 안될 수가 없는 문제라서 느긋하게 기다리면 될텐데요, 지금 이 시점에서 이런저런 예제를 만들어보고 있는 저로선 꽤나 골치아픈 문제네요. :(

    우선 현재 상황(Silverlight 1.1 Alpha)에서 Glyphs와 TextBlock의 차이점을 짚어보도록 할께요.
    구분 Glyphs TextBlock
    텍스트 지정 UnicodeString Text
    폰트 지원 FontUri;
    폰트의 경로를 지정 (ex: "MALGUN.TTF", "http://aa.bb.cc/fonts/MALGUN.TTF")
    FontFamily;
    폰트의 패밀리 이름을 지정 (ex: "맑은 고딕")
    다운로드 지원 미지원(정확하지는 않음) 지원, SetFontSource로 다운로드 받은 zip 패키지를 지정하고 그 안에 있는 폰트를 FontFamily속성에 지정할 수 있음.
    한글 지원 FontUri를 한글 폰트로 설정하면 모든 폰트를 지원 다운로드된 폰트를 사용하여도 Arial Unicode MS만이 한글 지원
    폰트 크기 FontRenderingEmSize;
    Em 단위로 지정(Word 등에서의 단위)
    FontSize;
    픽셀 단위로 지정
    폰트 색상 Fill;
    Brush
    Foreground;
    Brush
    기타 속성 지원
    • Indices; 어떤 역할인지 정확히 도큐멘팅 되지 않음.
    • StyleSimulations; 굵게, 이탤릭, 굵게/이탤릭만 지원
    • FontStretch; 1단계(50%)~9단계(200%)까지 늘이기
    • FontStyle; 이탤릭 지원
    • FontWeight; Thin에서 ExtraBlack까지 10단계 지원
    • TextDecoration; 밑줄 지원
    • TextWrapping; 텍스트 길이가 영역을 벗어날 때 자동 줄바꿈
    기타 OriginX, OriginY로 시작 위치 지정 TextBlock내부에 <LineBreak>나 <Run>로 줄바꿈 또는 다른 폰트 속성으로 텍스트를 표현 가능

    Glyphs는 TextBlock에 비해 상대적으로 표현 능력이 떨어지고 사용이 불편한데요, 다음과 같은 내용을 예로 들어볼게요.

    이름 : 공공도
    홈페이지 : gongdo.tistory.com
    전화번호 : 000-000-0000
    뭐 너무나도 일반적인 문장이죠? 이걸 Glyphs로 표현한다고 생각해보죠. 대충 이렇게 될 거에요.
    <Glyphs Canvas.Left="0", Canvas.Top="0", FontUri="Malgun.ttf" FontRenderingEmSize="10" StyleSimulations="Bold" UnicodeString="이름" />
    <Glyphs Canvas.Left="25", Canvas.Top="0", FontUri="Malgun.ttf" FontRenderingEmSize="10" StyleSimulations="None" UnicodeString=" : 공공도" />
    <Glyphs Canvas.Left="0", Canvas.Top="25", FontUri="Malgun.ttf" FontRenderingEmSize="10" StyleSimulations="Bold" UnicodeString="홈페이지" />
    <Glyphs Canvas.Left="100", Canvas.Top="25", FontUri="Malgun.ttf" FontRenderingEmSize="10" StyleSimulations="None" UnicodeString=" : gongdo.tistory.com" />
    ...생략...
    네, 위치를 일일히 수동으로 지정해야 하고 똑같은 속성을 몇 번이나 다시 써야 하죠? 이거 손으로 코딩이 가능할까요? 저라면 GG치겠어요.
    http://9eye.net/222 에 의하면 Office 2007 제품군의 XPS로 저장하기 기능을 사용하여 어느 정도 편해질 수는 있어요.
    위와 같은 예제를 워드 2007로 만들어 보죠.

    참 쉽죠? 그리고 XPS로 저장한 뒤에 XPS의 압축을 풀고 Documents\1\Pages\1.fpage를 메모장에서 열어보죠.


    ...이젠 별로 안쉽죠? 저 엄청난 양의 코드를 보세요(덜덜덜). Copy&Paste는 별 문제 안되겠지만 내용을 바꾼다고 생각해보세요.

    네, Glyphs의 문제는 고정된 디자인을 만들기는 그렇게 어렵지 않지만 이걸 동적으로 내용을 바꾸기엔 너무나도 부담스럽다는 거에요.
    사실 Glyphs 자체가 이런 동적인 문자열 포매팅을 위한 클래스도 아니지만요.
    Glyphs는 위치가 정해진 텍스트를 딱 한 줄로 표현할 때만 사용하는 게 올바른 사용 방법일 것 같습니다.

    그럼 TextBlock으로는 위의 예제를 쉽게 작성하고 쉽게 변경할 수 있을까요? 예제 코드를 만들어보죠.
    <TextBlock x:Name="form" FontFamily="Arial Unicode MS" FontSize="15">
        <Run FontWeight="Bold" Text="이름ABC" />
        <Run Text=" : " />
        <Run x:Name="formName" Text="공공도" />
        <LineBreak />
        <Run FontWeight="Bold" Text="홈페이지" />
        <Run Text=" : " />
        <Run x:Name="formHomepage" Text="gongdo.tistory.com" />
        <LineBreak />
        <Run FontWeight="Bold" Text="전화번호" />
        <Run Text=" : " />
        <Run x:Name="formPhone" Text="000-000-0000" />
        <LineBreak />
    </TextBlock>
    문장의 의미가 좀 더 명확해졌고 각 텍스트의 위치는 자동으로 계산되어 배치되며 LineBreak로 줄 바꿈도 가능해요. 또 개별 요소들도 x:Name을 지정할 수 있으니 코드-비하인드에서 원하는 내용의 수정도 덜 괴롭겠구요.
    한번 실행해 볼까요?


    아뿔싸... 이런 낭패가! Bold가 안먹네요. Thin, ExtraBlack, 및 이탤릭 등 어떤 속성도 제대로 적용되지 않더군요.
    불행중 다행은 폰트 사이즈는 개별 설정이 된다는 점.


    보시다시피 폰트 사이즈가 달라져도 폰트 배치는 자동으로 된다는 걸 확인할 수 있어요.
    TextBlock이 스펙대로의 동작만 정확히 하고 폰트 문제만 해결된다면 상당히 해피해질텐데 정식판은 아직 멀었을까요. 휴우휴우.

    결론을 내려보자면 아직은 텍스트의 동적이고 구조적인 표현은 불가능하진 않지만 어차피 정식판에서 쉽게 해결 될 수 있는 문제이기 때문에 그렇게 노력을 들여 구현할 만큼의 가치는 전혀 없다는 겁니다.
    꼭 지금 당장 Silverlight로 한글을 표현해야 한다면 가급적 단순한 출력의 레이아웃을 잡고 Glyphs를 활용하는게 좋을 것 같고, 가장 좋은 방법은 정식판에서 TextBlock이 정상적인 작동을 하길 기다리는 것일 것 같네요.


    보너스.
    현재 TextBlock에서 한글을 표시할 수 있는 Arial Unicode MS 폰트는 무려 22메가나 돼요.
    이걸 다운로드 하라고 하는건 거의 자살행위나 마찬가지겠죠?
    그래서 워드와 XPS 출력을 이용해 필요한 글자만 들어있는 odttf 파일을 추출해봤어요.
    여기서 사용가능한 글자의 목록은 아래와 같습니다.
    • 모든 Unicode 한글 문자와 자음/모음
    • 일반적인 한글 폰트에서 지원하는 기호와 특수문자
    • 키릴 문자
    • 일본어 히라가나/가타가나
    위 내용을 포함하도록 패키징해보니 단지 1.6메가로 완성되더군요!
    게다가 이걸 압축해보면 500kb도 안나옵니다. 굉장히 고무적이죠!
    하지만 이 odttf에는 한자는 한글자도 안들어갔어요.
    한자는 폰트 밀도가 높아서인지 19메가에 달하고 압축해도 14메가정도더군요.
    그래서 한자는 뺐습니다.
    어쨌든 받아서 테스트 해보실 분은 아래 파일을 받으세요.
    한글일반.zip

    일반적인 한글 표현을 위한 odttf


    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    이벤트 핸들링
    준비 사항
    Silverlight 개발의 기초에서 개발에 필요한 도구와 기술에 대해 설명하고 있습니다.

    이벤트 핸들링 방식

    이벤트 핸들러
    이벤트 핸들러는 하나의 Silverlight 페이지 내에 존재하는 개체들의 이벤트를 처리하는 코드-보통은 함수-를 말합니다. Silverlight의 페이지 또는 컨트롤은 하나의 XAML 파일로 표현되며 이 마크업 내에서 표현되는 모든 개체는 자신이 노출하는 이벤트에 대한 이벤트 핸들러를 지정할 수 있습니다. 이런 개체는 코드-비하인드에서도 같은 클래스명을 가진 개체로 참조가 가능하고 반대로 코드-비하인드에서 동적으로 개체를 추가할 수도 있습니다.

    Silverlight 개발의 기초; Hello Silverlight! 에서는 별다른 설명도 없이 이벤트 핸들러를 사용하였고 사실 특별한 설명이 필요 없을 정도로 직관적이었죠. 이렇게 Silverlight 내의 컨트롤의 이벤트를 처리 하는 방법은 몇 가지가 있습니다.
    • Silverlight 브라우저 컨트롤(HTML 페이지)에 의해 인터프리트되는 JavaScript 핸들러를 이용.
    • IronPython, 매니지드 JScript와 같은 다이내믹 언어로 작성한 핸들러를 이용. 이 핸들러는 런타임이 되기 전 까지 컴파일 되지 않으며 DLR(Dynamic Language Runtime)에 의해 제공됩니다. 자세한 건 http://silverlight.net/QuickStarts/Other/ProgramDlr.aspx 여기를 참조하시고요, DLR에 대해서는 아마도 다루지 않을 것 같네요.
    • C#과 VB.NET같은 매니지드 코드 언어로 작성한 핸들러를 이용. 이 핸들러는 라이브러리 파일(.dll)로 컴파일되며 XAML에서 구현된 라이브러리를 참조하여 사용합니다. 빌드시 라이브러리로 컴파일 되므로 소스코드를 공개하지 않고 배포할 수 있습니다.
    이 글에서는 Silverlight 1.1에서 지원하는 C#을 사용한 매니지드 코드로 작성할 수 있는 이벤트 핸들링에 대해 설명합니다.

    이벤트 핸들러의 구현 방법
    매니지드 코드에서 이벤트 핸들러를 구현하는 방법은 크게 두 가지가 있습니다.
    • 마크업의 개별 엘리먼트에서 이벤트 핸들러를 지정하는 어트리뷰트에 이벤트 핸들러의 이름을 지정하고 코드-비하인드에서 해당 이름의 이벤트 핸들러 함수를 정의하는 방법.
    • 코드-비하인드에서 원하는 개체의 참조로부터 이벤트 핸들러 델리게이트를 구현하는 방법.
    이 이벤트 핸들러를 구현하는 방법을 알아보기에 앞서 이벤트 핸들링의 대상이 되는 개체가 어떻게 참조되는지 알아보겠습니다.

    코드-비하인드에서 개체 참조하기

    개체의 이름
    마크업과 코드-비하인드 모두에서 어떤 개체를 표현할 수 있고 이 개체는 '이름'을 가질 수도 있고 그렇지 않을 수도 있습니다. 각각의 예를 들어보죠.
    XAML
    <!-- 이름이 없는 엘리먼트 -->
    <TextBlock Text="Text Content" />

    <!-- 이름을 지정한 엘리먼트 -->
    <TextBlock x:Name="Content" Text="Text Content" />

    C#
    // 이름이 없는 TextBlock을 메인 캔버스에 추가
    mainCanvas.Children.Add(new TextBlock());
    // 이름이 있는 TextBlock을 생성하고 속성 지정
    TextBlock content = new TextBlock();
    content.Text = "Text Content";

    이름이 없는 개체는 다시 말해 그것이 화면에 표시되거나 어떤 기능을 가진다고 해도 코드에서 개별적으로 접근될 필요가 없다는 것을 의미합니다. 반대로 이름이 있다는 것은 그 개체를 식별하고 싶다는 것을 말하며 코드에서 언젠가는 그 개체의 이름을 불러 참조하고 싶다는 것을 의미합니다. 생각해보면 당연하겠죠?

    일반적으로 개체의 이름은 디자인 타임에만 명시적으로 지정할 수 있으며 마크업에서 정의한 엘리먼트의 이름은 해당 마크업에서 정의한 x:Class의 멤버로 선언됩니다. 하지만 코드-비하인드에서는 어떤 프로시저 내에서 선언하여 한시적인 스코프를 가질 수도 있고 마크업의 x:Class에서 정의한 클래스의 멤버로 선언하여 애플리케이션 내내 그 이름을 유지할 수도 있습니다.

    개체 트리(Object Tree) 구성
    Canvas와 같은 컨테이너 역할을 하는 개체는 다른 개체들을 자식으로 포함할 수 있습니다. 예를 들어 어떤 페이지에 텍스트블럭과 사각형 도형을 가진 캔버스는 다음의 마크업과 같이 표현할 수 있습니다.
    XAML
    <Canvas>
      <TextBlock Text="Text Content" />

      <Rectangle Width="100" Height="100" />
    </Canvas>

    이 때 개체들은 트리 구조를 이루게 되며 이것을 개체 트리(Object Tree)라고 합니다.

    좀더 구체적으로 코드상에서 Canvas 개체는 Panel 개체를 상속하고 있으며 이 Panel 개체는 다른 개체의 컨테이너를 제공하고 컨테이너에 포함된 자식 개체들을 Children 이라는 프로퍼티를 통해 Collection으로 제공합니다.

    위의 개체들을 간략하게 그려보자면 다음과 같은 트리 구조로 표현할 수 있습니다.


    이름이 없는 개체 참조하기
    Silverlight 페이지의 일반적인 루트 엘리먼트인 Canvas는 Panel을 상속하여 구현되었으며 Panel 클래스의 Children 프로퍼티를 사용하여 자식 엘리먼트를 열거할 수 있습니다.

    따라서 특별히 개체의 이름을 지정하지 않더라도 Children 프로퍼티를 통해 다음과 같이 접근이 가능합니다. (여기에서 루트 개체는 Canvas이고 this 키워드로 접근했다고 가정합니다.)
    C#
    // 루트 개체로부터 자식의 인덱스로 접근
    TextBlock tb = this.Children[0] as TextBlock;
    Rectangle rt = this.Children[1] as Rectangle;

    // 루트 개체의 모든 자식을 열거하면서 처리
    foreach (Visual vi in this.Children)
    {
        // 각 자식 개체를 vi로 참조하여 처리...
    }

    이 방법으로 개별 개체에 접근하기란 매우 불안정합니다. 보시다시피 자식의 인덱스 번호 즉, 해당 개체가 컨테이너에 추가된 순서를 미리 알고 있어야 한다는 전제 조건이 생기며 만약 디자인이 변경된 경우 이 인덱스가 바뀔 가능성이 높으므로 이런 방법은 사용하지 않는 것이 좋습니다. 앞서서 얘기 했지만, 어떤 개체에 개별적으로 접근할 때에는 반드시 이름을 지정하는 것이 좋습니다.

    다만 예제의 두번째 블럭처럼 모든 자식을 열거하면서 공통적인 처리를 할 때에는 좋은 수단이 될 수 있을 것입니다.

    이름이 있는 개체 참조하기1 - Children 프로퍼티를 사용
    다음 마크업과 같이 특정한 이름을 지정한 경우는 좀 더 명확한 접근이 가능합니다.
    XAML
    <Canvas>
      <TextBlock x:Name="Content" Text="Text Content" />

      <Rectangle x:Name="Banner" Width="100" Height="100" />
    </Canvas>

    C#
    // 루트 개체로부터 자식의 명시적인 이름으로 접근
    TextBlock tb = this.Children.FindName("Content") as TextBlock;
    Rectangle rt = this.Children.FindName("Banner") as Rectangle;

    이름 없는 개체에 접근할 때와 비슷하지만 FindName이라는 메소드를 사용하여 좀 더 명시적인 접근이 가능합니다. 하지만 이 경우도 마크업과 코드-비하인드 간의 동기화 문제는 여전히 남아 있어서 만약 마크업을 수정한 경우 코드-비하인드 역시 수정되어야 하며 컴파일러가 해당 이름의 개체가 있는지 여부를 체크할 수 없습니다.

    결정적으로 마크업에서 명시적으로 이름을 지정한 개체를 이렇게 접근해야 할 이유는 단 한가지도 없다고 단언할 수 있으며 그 이유는 다음과 같습니다.

    이름이 있는 개체 참조하기2 - 컴파일러가 자동으로 생성하는 멤버 변수
    마크업에서 x:Name 어트리뷰트로 지정된 이름은 마크업의 루트 엘리먼트가 지정한 x:Class에 해당하는 코드-비하인드 클래스의 멤버로 구현됩니다. 이 과정은 컴파일 도중 컴파일러에 의해 자동으로 구현되며 따라서 개발자는 코드-비하인드에 별도의 코드를 작성하지 않고도 x:Name에서 지정한 이름을 곧바로 사용할 수 있습니다.

    이것은 매니지드 언어가 지원하는 partial class 선언 덕분에 가능한 일인데요, 이 과정을 살펴보면 다음과 같이 요약할 수 있습니다.

    1. 마크업에서 x:Name 어트리뷰트로 개체의 이름을 지정.
    2. 컴파일러는 빌드시 자동으로 x:Class에서 지정한 클래스 이름으로 partial 클래스를 생성하고 위의 개체를 클래스의 멤버 변수로 선언.
    3. 코드-비하인드에 초기화 코드를 호출.
    4. 자동으로 생성된 코드에서 FindName을 통한 개체 찾기를 통해 멤버 변수에 참조를 설정.
    5. 코드-비하인드에서는 자동으로 생성된 클래스의 멤버 변수를 직접 접근하여 사용.
    개체 참조 방식 비교
    Children을 사용한 개체 참조 방법은 런타임에 동적으로 일어나므로 꼭 필요할 때에만 참조를 만들게 되므로 페이지에 컨트롤 해야 할 개체가 아주 많다면 최초 페이지 로딩시 참조 생성작업이 필요 없어서 초기화 속도상의 이점이 있고 아주 약간의 메모리 절감 효과가 있습니다. 반면 실제 개체를 접근 할 때 동적으로 컬렉션을 뒤지는 작업을 해야 하므로 접근 속도가 느리고 마크업이 변경된 경우 컴파일 시점에 그 사실이 반영되었는지 알 수 없으므로 디버깅에 불리합니다.

    컴파일러가 자동으로 생성해주는 멤버 변수를 사용한 개체 참조 방법은 위와 반대로 페이지에 아주 많은 개체가 있다면 초기화에 약간의 시간이 더 걸리고 참조 변수 자체의 메모리가 더 필요한 반면 개체에 대한 접근은 참조를 통해 상수적으로(Constantly) 이루어지므로 빠르게 처리할 수 있습니다.

    하지만 여러가지 조건과 득실을 따져보자면 후자의 방법이 전자에 비해 월등한 이점이 있다고 봅니다. 특히 후자의 방법은 컴파일러에 의해 해당 개체가 자동으로 생성되므로 만약 마크업에서 해당 개체를 삭제한다면 그 개체를 사용했던 기존 코드는 컴파일 시점에 에러를 낼 것이고 이는 훨씬 안전하고 견고하며 빠르게 디버깅 할 수 있는 기반이 됩니다.

    이벤트를 핸들링하는 방법

    이벤트 핸들러의 기본 형식
    Silverlight에서 모든 개체의 이벤트 핸들러는 다음과 같은 형식을 가집니다.
    void EventHandler(object sender, EventArgs e)

    첫번째 파라미터는 이벤트를 발생시킨 개체를 참조하며 만약 그 이벤트를 발생시킨 개체를 정확히 알고 있다면 그 개체의 타입으로 캐스팅하여 추가적인 작업을 편하게 할 수 있습니다.

    두번째 파라미터는 이벤트의 추가 정보로 EventArgs 타입을 상속받아 구현되는 개체입니다. 물론 이 개체는 발생되는 이벤트의 종류에 따라 다를 것입니다. 예를 들어, 마우스 왼쪽 버튼이 눌렸음을 알리는 이벤트 개체는 MouseEventArgs 클래스이고 키보드 버튼이 눌렸음을 알리는 이벤트 개체는 KeyboardEventArgs 클래스입니다. 추가적인 정보가 전혀 없는 GotFocus 이벤트라고 해도 null을 참조하는 EventArgs 개체가 전달됩니다.

    첫번째 파라미터가 object 타입으로 지정되어 있으므로 동일한 작업을 수행한다면 다수의 개체의 이벤트 핸들러를 동일하게 지정할 수 있습니다. 여기에 대한 예제는 이 절의 마지막에서 설명합니다.

    이벤트 핸들러는 각 개체마다 여러가지 종류가 있지만 여기서는 대부분의 개체가 지원하고 누구나 이해하기 쉬운 왼쪽 마우스 버튼을 눌렀을 때 발생하는 이벤트인 'MouseLeftButtonDown' 이벤트를 통해 알아보도록 하겠습니다.

    시나리오는 TextBlock을 하나 올리고 마우스로 클릭했을 때 "Mouse Left Button Down!" 라고 표시하는 예제입니다.

    마크업에서 이벤트 핸들러를 지정하는 방법
    이 방법은 마크업의 이벤트 핸들러 어트리뷰트를 선언하고 이벤트 핸들러의 이름을 지정한 후 코드-비하인드에 해당 이벤트 핸들러를 작성합니다. 아마 이 방법은 HTML과 JavaScript로 이벤트 처리를 해보신 분이라면 쉽게 이해할 수 있을 것이고 실제로 코드도 거의 동일합니다.

    이 예제 프로젝트는 아래에서 다운 받으세요.
    EventHandling1.zip

    이벤트 핸들링 방법 1



    Howto:2-1. 마크업에서 이벤트 핸들러를 지정한 처리 방법
    ※ 각 단계에서의 코드는 아래의 XAML과 C# 코드를 참고하세요.
    1. 마크업에서 원하는 엘리먼트(개체)에 MouseLeftButtonDown 어트리뷰트를 선언하고 이벤트 핸들러의 이름을 지정합니다.
        <TextBlock Text="Text Content1" MouseLeftButtonDown="OnMouseLeftButtonDown" />
    2. 코드-비하인드에 위에서 지정한 이름의 이벤트 핸들러 프로시저를 작성합니다.
    3. sender를 TextBlock으로 캐스팅하고 Text 속성을 변경합니다.
        void OnMouseLeftButtonDown(object sender, MouseEventHandler e)
        {
            TextBlock tb = sender as TextBlock;
            tb.Text = "Mouse Left Button Down!";
        }

    XAML
    <Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="EventHandling.Page;assembly=ClientBin/EventHandling.dll"
        Width="640" Height="480" Background="White" >

        <TextBlock Canvas.Top="10" Text="Text Content 1" MouseLeftButtonDown="OnMouseLeftButtonDown" />
    </Canvas>

    C# (※ using 구문과 namespace를 생략했습니다.)
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();
        }

        // TextBlock1
        void OnMouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            TextBlock tb = sender as TextBlock;
            tb.Text = "Mouse Left Button Down!";
        }
    }

    이 방식은 아무런 참조 없이 코딩하기가 상당히 머리아픕니다. 예제에서 MouseLeftButtonDown 이벤트의 처리를 보였는데 만약 키보드 입력을 처리하려면 또, MouseLeftButtonUp 이벤트를 처리하려면 어떤 EventArgs 타입을 사용해야 하는지 개발자가 미리 알고 있어야 한다는 걸 전제한다는 것이죠.

    다음 방법은 좀 더 경쾌한 코딩을 할 수 있게 합니다.

    코드-비하인드에서 이벤트 핸들러를 붙이는(Attatch) 방법
    이 방법은 마크업에서 별도로 지정하지 않고 코드-비하인드에만 코드를 작성하여 이벤트 핸들러를 작성하고 붙입니다. C#에서 일반적인 이벤트 핸들러나 델리게이트를 사용하는 방법과 동일하며 전자에 비해 인텔리센스를 통한 코드 자동완성 기능을 지원하고 이벤트 핸들러의 기본형도 자동으로 만들어 주는 이점이 있습니다.

    이 예제 프로젝트는 아래에서 다운 받으세요.
    EventHandling2.zip

    이벤트 핸들링 방법 2



    Howto:2-2. 코드-비하인드에서 이벤트 핸들러를 붙이는 방법
    ※ 각 단계에서의 코드는 아래의 XAML과 C# 코드를 참고하세요.
    ※ 코드는 위에서 작성한 코드에 이어서 작성합니다.
    1. 마크업에는 단지 제어할 엘리먼트만 올려놓습니다. 이 엘리먼트에 x:Name 어트리뷰트를 선언하는 것은 선택적이지만 가급적 선언하는 것이 코드를 작성하기 수월합니다. 여기에서는 x:Name을 지정한 걸로 진행합니다.
        <TextBlock x:Name="text2" Text="Text Content2" />
    2. 코드-비하인드의 초기화 코드에서 위의 엘리먼트를 참조하는 개체에 이벤트 핸들러를 작성합니다. 인텔리센스의 코드 자동완성 기능을 사용하면 다음 문장까지 입력하고 탭, 탭을 누르면 됩니다.
        text2.MouseLeftButtonDown += 
    3. 자동으로 작성된 이벤트 핸들러에 코드를 기입합니다.
        text2.Text = "Mouse Left Button Down!";

    XAML
    <Canvas x:Name="parentCanvas"
        xmlns="http://schemas.microsoft.com/client/2007"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="EventHandling.Page;assembly=ClientBin/EventHandling.dll"
        Width="640" Height="480" Background="White" >

        <TextBlock Canvas.Top="10" Text="Text Content 1" MouseLeftButtonDown="OnMouseLeftButtonDown" />
        <TextBlock x:Name="text2" Canvas.Top="30" Text="Text Content 2" />
    </
    Canvas>

    C# (※ using 구문과 namespace를 생략했습니다.)
    public partial class Page : Canvas
    {
        public void Page_Loaded(object o, EventArgs e)
        {
            // Required to initialize variables
            InitializeComponent();
            text2.MouseLeftButtonDown += new MouseEventHandler(text2_MouseLeftButtonDown)
        }

        // TextBlock1
        void OnMouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            TextBlock tb = sender as TextBlock;
            tb.Text = "Mouse Left Button Down!";
        }

        // 코드 자동완성 기능에서 만들어준 핸들러에 처리할 내용만 직접 작성
        void text2_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            text2.Text = "Mouse Left Button Down!";    // 이미 대상 개체 참조를 알고 있으므로 캐스팅할 필요 없음
        }
    }

    Note
    ※ VS를 익숙하게 써보셨다면 위의 코드 자동완성에 대해 잘 아시겠지만 잘 감이 안오시는 분들을 위해 작업을 동영상으로 캡쳐해봤습니다.
    정말이지 이런 기능 없을 땐 어떻게 살았나 싶네요. ^_^

    이벤트 핸들러 방식의 비교
    이 두가지 방식의 이벤트 핸들러 처리는 앞서 얘기했던 Children을 통해 개체의 참조를 획득하느냐 아니면 x:Name을 통해 개체의 참조를 획득하느냐의 차이와 비슷한 차이점을 가지고 있습니다.

    그런데 이 이벤트 핸들링 방식의 경우 후자의 방식이 모든 면에서 완전히 더 유용하고 편리하고 정확하다고 생각합니다. 아마도 전자의 방법은 기존의 HTML/JavaScript 문법과 유사한 경험을 제공하기 위한 일종의 Legacy 지원이라고 봐도 될 것 같습니다.

    그런 이유로 앞으로 진행하는 모든 Silverlight 프로젝트는 이벤트 핸들링에 있어서 만큼은 후자의 방식을 사용할 예정입니다.

    참고

    Silverlight 공식 QuickStarts 참고:
    http://silverlight.net/QuickStarts/BuildUi/ControlEventHandlers.aspx
    http://silverlight.net/QuickStarts/BuildUi/CallJavascript.aspx

    Silverlight 레퍼런스 Events Overview:
    http://msdn2.microsoft.com/en-us/library/bb412396.aspx

    WPF에서 XAML 코드가 컴파일 될 때 내부 동작 참고:
    http://gongdo.tistory.com/74
    http://gongdo.tistory.com/82

    Posted by gongdo
    Silverlight가 아직은 베타/알파 버전이라 많은 부분 부족함을 느끼고 있어요.
    그 중에서 당장 가장 크게 느껴지는 문제점은 화면에 텍스트를 표시하는 TextBlock 엘리먼트에서 한글 폰트를 지원하지 않고 있다는 점인데요, http://uxkorea.net/blog_post_62.aspx 에 의하면 TextBlock 대신 Glyph 엘리먼트를 사용하면 한글 폰트도 사용 가능하다고 합니다. 테스트 해봤는데 잘 먹더군요.

    하지만 Glyph는 TextBlock과는 그 성격이 약간 다른데요, 나중에 따로 포스팅 하겠지만 간단히 말해서 TextBlock은 일반적인 TextBox와 비슷하게 멀티 라인 텍스트와 텍스트 블럭내의 각각의 텍스트에 다른 폰트 설정을 추가할 수 있고 Glyph는 단순히 지정된 텍스트를 지정된 위치에 출력할 뿐입니다. 두 엘리먼트 모두 TrueType폰트만 표시가 가능하고요.

    그래서 여러 라인을 출력할 때 Glyph는 각 라인마다 출력될 Top 좌표를 직접 계산해줘야 해서 보통 귀찮은게 아니에요. TextBlock은 멀티 라인을 사용할 때 각 라인은 기본적으로 폰트특성에 따라 자동 계산되죠.

    구글링을 통한 대부분의 의견도 동아시아와 중동아시아의 폰트가 제대로 표시할 수 없다 였는데요, 일부는 특정 폰트가 정상적으로 표시된다는 의견도 있어서 테스트를 해봤습니다.

    일단 시스템 내의 모든 TrueType 폰트 목록을 정리해서 테스트 페이지에 순서대로 영어, 숫자, 특수문자, 한글, 한자, 일본어, 중국어를 출력해보는거죠.
    당연하겠지만 Silverlight는 웹 애플리케이션으로 사용자의 로컬 자원에 접근할 수 없어요. 폰트 목록 같은걸 가져오는건 동적으로 불가능해서 제 시스템에 설치된 200여개의 폰트 목록을 수작업으로 정리했습니다. ㅠ.ㅜ

    출력할 텍스트 내용은
    English 12345 한글문자열가나다라 ☆★○◎ 漢字家羅多螺 日本語にほんご 中国语你好吗
    위와 같고요, 테스트한 동영상을 감상하시죠!


    보시다시피 200개도 넘는 폰트 중에 한글을 지원하는건 Arial Unicode MS 뿐이었습니다.
    요게 뭔가...하면 Wiki를 참고하세요. http://en.wikipedia.org/wiki/Arial_Unicode_MS
    대략 특징을 요약하자면,
    - 트루타입 유니코드 폰트
    - 대부분의 Microsoft 코드 페이지를 지원
    - 22메가!!
    - Ascender Corporation에서 오직 MS에만 라이센스함

    뭐 그나마도 지금 당장 써먹을 수 있는게 있으니 얼마나 다행인가 싶으시죠?

    하지만 문제는 또 있어요.
    역시 나중에 포스팅 할 꺼리지만(-_-) Silverlight는 폰트의 배포를 위한 다운로드 매커니즘을 지원해주고 있어요. 그래서 사용자의 PC에 내가 원하는 폰트를 배포하고 UI를 망치지 않고 표시해줄 수 있죠.

    문제는 이 Arial Unicode MS 폰트의 크기가 무려 22메가에 달한다는 점이에요.
    당연하죠. 웬만한 코드 페이지는 몽땅 표시해주는데 22메가면 오히려 작은 크기라고 할 수 있죠. New 굴림 폰트만해도 25메가나 되는데요 뭘.
    그.러.나. 이게 웹을 통해 동적으로 배포된다고 생각해보세요. 22메가를 다운받을 동안 기다릴 사용자가 있을까요? 과연?

    물론 1.0 정식 버전과 1.1(아마도)베타 버전에서는 이런 폰트 표시 문제가 해결될거라고 기대되지만, 아직도 문제는 더 있어요.
    정식 버전에서 폰트 지원이 완벽하더라도 보통 한글 폰트는 용량이 무지하게 커요. 좀 예쁘다 싶은 폰트를 보면 죄다 5메가 이상이죠. 이건 한자 문화권의 어쩔 수 없는 문제이긴 하지만요.

    하다못해 굴림/굴림체/돋움/돋움체/바탕/바탕체/궁서/궁서체/새굴림/맑은고딕 정도는 별도로 다운로드 받지 않더라도 세팅해서 사용할 수 있게 해줬으면 해요. 과연 어떻게 될까요? 저는 좀 비관적으로 보고 있지만요.


    결론을 얘기해보자면 '한글은 현재 샘플/테스트용만 가능해요. 실제 서비스따위 아직은 무리라구요!'
    airlover님의 트랙백에 의하면 Office에서 XPS문서로 저장했을 때 나온 결과물을 적절히 가공하여 Glyph와 .odttf라는 임시 폰트로 정리되어 용량도 비교적 작고 자유로운 편집(Office에서 편집하니까)이 가능하다고 하네요.

    수작업이 좀 많이 들어가긴 하지만 이 방법이라면 실제 서비스도 가능하다고 봅니다. (다만 뭔가 디자인적인 수정이 생기면 괴롭긴 마찬가질 것 같아요.)

    정말이지 MS 제품군간의 연동으로 얻을 수 있는 시너지란;;;

    아래에 테스트에 사용한 프로젝트를 첨부했어요.
    물론 100메가도 넘는 폰트들을 전부 첨부하지 못했고 저용량 폰트 몇개만 넣었어요.
    테스트 하실 땐 프로젝트 폴더에 테스트하길 원하는 폰트들을 Fonts.zip으로 압축해서 복사해놓고 프로젝트의 Page.xaml.cs에서 _fontList 변수에 해당 폰트의 이름을 적어주세요.
    테스트를 위해 날림으로 작성한 코드라 별도의 설명은 붙이지 않았으니까 양해해주시고 여기서 사용된 기술들은 정리해서 포스팅할 예정이에요. QuickStarts 시리즈부터 해야죠.;;
    TestText.zip

    TextBlock과 한글 문제 테스트 프로젝트

    Posted by gongdo
    Silverlight 1.1 바로 시작하기

    Silverlight 개발의 기초
    준비 사항

    Silverlight 개발 환경
    먼저 개발에 필요한 환경을 갖춰야겠죠?
    현재 Silverlight은 자바스크립트만으로 컨트롤이 가능한 1.0 beta 버전과 매니지드 코드 즉, CLR환경과 통합되는 1.1 alpha 버전으로 나누어져 있습니다. 여기에서는 1.1 alpha를 기준하겠습니다.

    필요한 모든 파일은 http://msdn2.microsoft.com/en-us/asp.net/bb187452.aspx 여기에서 다운받을 수 있어요.

    먼저 실제 개발에 필요한 툴. 다음으로 디자인에 필요한 툴. 마지막으로 Silverlight SDK인데요, QuickStarts에 있는 내용과 샘플이 대부분입니다. 개발시 최소한 모든 개발 툴과 Expression Blend는 있어야 편합니다.
    그 외에 illustrator나 플래쉬 SWF파일을 XAML로 변환해주는 툴들도 있으니 참고하세요.

    Silverlight를 시작하기 전에
    먼저 Silverlight가 도대체 뭐 하는 넘인가부터 알아야겠죠? 하지만 이 주제는 너무나 일반적이고 다른 곳에서 더 잘 정리되어 있으니 굳이 여기에서 다시 얘기하지 않는 게 좋을 것 같습니다.

    Silverlight 개발을 시작하기 전에 먼저 아래의 내용들을 둘러보세요.
    • Silverlight 및 XAML에 대한 전반적인 소개
      http://msdn.microsoft.com/msdnmag/issues/07/06/Silverlight/Default.aspx?loc=ko
      여기에서 Silverlight와 XAML에 대한 소개 부분만 읽어보시면 돼요.
    • WPF 및 XAML 다루는 예제
      http://hoons.kr, http://visumuri.net 같은 커뮤니티의 WPF 강좌에서 XAML을 다루는 방법을 익혀두시는 게 좋아요. Silverlight에서 지원하는 엘리먼트가 적긴 하지만 기본적인 사용방법은 크게 차이 나지 않으니 도움이 될 거에요.
    • Silverlight 공식 QuickStarts 페이지
      http://silverlight.net/quickstarts/managed.aspx
      이 글의 기반이 되는 공식 페이지입니다. 미리 얘기 드리자면 이 글은 이 페이지의 내용을 기반으로 제가 나름대로 편집하고 추가한 거에요. 대부분 HowTo형식으로 작성되어 있으니 따라 하는데 별다른 어려움은 없으니 이 페이지를 닫고 이걸로 공부하시는 것도 좋은 방법이죠.
    • Silverlight MSDN 페이지
      http://msdn2.microsoft.com/en-us/library/bb188743.aspx
      MS 기술 개발자라면 자연스럽게 사용해야 할 MSDN입니다. 아직 Silverlight 1.1(with .NET)은 개체 레퍼런스가 나와있지 않은데요 기본적으로 Javascript 버전과 개체의 이름과 내용은 거의 동일하므로 Javascript 버전을 참고해야 할거에요.
    사전 지식
    Silverlight는 워낙 고수준의 추상화가 잘 되어 있는데다가 Visual Studio의 막강한 IDE덕분에 쉽게 접근할 수 있다고 생각해요.
    하지만 기본적으로 HTML/Javascript/XML에 대해 개념 정도는 파악하고 있어야겠고요, 매니지드 코드를 다루기 위해 C#(혹은 VB)를 어느 정도는 다룰 수 있어야 해요. 이 글에서는 말 그대로 곧바로 시작하기 위해 이런 기반 기술에 대한 설명은 최대한 줄일 생각이에요.

    Silverlight 1.1 프로젝트 구성

    기본 프로젝트 템플릿 구성
    앞서 말한 개발 환경을 갖추고 Visual Studio codename "Orcas"(이하 Orcas)를 실행하고 새 프로젝트를 선택해보면 Silverlight 프로젝트 템플릿이 보입니다. 현재 Silverlight 1.1에서 지원하는 CLR은 C#과 VB.NET이 있는데요, 앞으로의 모든 내용은 C#을 기준으로 합니다. 긴말 할 필요 없이 만들어 볼까요?

    Howto:1-1. 새 Silverlight 프로젝트 만들기
    1. Orcas를 실행합니다.
    2. 메뉴에서 File->New->Project를 선택하거나 Ctrl+Shift+N를 눌러 새 프로젝트를 선택합니다.
    3. 새 프로젝트 다이얼로그 박스에서 Project types를 Visual C#->Silverlight로 선택하고 Templates에서 Silverlight Project를 선택한 후 [OK]를 누릅니다.
    사용자 삽입 이미지


    프로젝트를 생성한 후 우측 상단에 있는 솔루션 익스플로러를 보면 다음과 같은 파일로 구성되어 있습니다.
     
    • TestPage.html
      Silverlight 애플리케이션을 테스트하기 위한 HTML 파일로 브라우저에서 최초로 실행되는 엔트리 포인트의 역할을 합니다. 일반적으로 Silverlight 페이지를 호스팅할 HTML 파일은 Silverlight.js와 Silverlight 페이지를 생성하는 자바 스크립트 파일을 포함하며 Silverlight 페이지는 보통 임의의 DIV 태그 안에 호스팅됩니다.
    • TestPage.html.js
      Silverlight 페이지를 생성하기 위한 createSilverlight 메소드를 제공하는 자바 스크립트 파일입니다. 내부적으로 Silverlight.js에서 제공하는 createObject 혹은 createObjectEx 메소드를 사용하여 지정된 XAML 파일 및 설정으로 Silverlight 페이지를 생성합니다. 이 메소드의 내용은 애플리케이션마다 변경될 수 있으므로 각 Silverlight 애플리케이션마다 고유한 스크립트 파일을 생성합니다.
    • Silverlight.js
      Silverlight 컨트롤을 생성하여 HTML 페이지로 호스팅하기 위한 자바 스크립트 파일입니다. 이 파일은 모든 프로젝트에서 공통으로 사용되므로 사이트의 특정 위치에 놓고 include 하여 사용하는 게 좋습니다.
    • Page.xaml
      createSilverlight 메소드 호출을 통해 HTML 페이지에 호스팅될 Silverlight 컨텐츠입니다. 이 마크업의 루트 엘리먼트는 반드시 xmlns 어트리뷰트로 올바른 네임스페이스를 지정해줘야 합니다. 일반적으로 Silverlight 페이지의 루트 엘리먼트는 다른 개체를 담을 수 있는 Canvas를 사용합니다. Silverlight 애플리케이션이 매니지드 코드를 사용하므로 루트 엘리먼트는 반드시 x:Class 어트리뷰트를 포함해야 합니다. 나중에 설명하겠지만 x:Class 어트리뷰트는 코드-비하인드에서 사용될 클래스 명을 식별하는데 사용됩니다.
    Silverlight 1.1은 매니지드 코드를 사용하며 위의 XAML 파일을 핸들링하는 코드-비하인드 파일을 포함합니다.
    • Page.xaml.cs (또는 .vb)
      이 파일은 런타임에 이벤트를 핸들링하는 매니지드 코드를 제공하며 반드시 Page.xaml에서 정의된 x:Class와 동일한 이름의 partial 클래스를 정의해야 합니다. 이 매니지드 코드는 외부로 배포할 필요가 없으며 마크업에서 정의된 assembly만 배포하면 됩니다.
    페이지 추가하기
    필요에 따라 한 HTML 페이지 내에 여러 개의 Silverlight 컨트롤을 호스팅하거나 호스팅된 Silverlight 페이지내에서 다른 Silverlight 페이지로 내비게이팅할 수 있을 것입니다.
    Howto:1-2. 새 Silverlight 페이지 추가하기
    1. 메뉴에서 Project->Add New Item을 선택하거나 Ctrl+Shift+A를 눌러 새 아이템을 선택합니다.
    2. 새 아이템 다이얼로그 박스에서 Silverlight Page를 선택하고 [OK]를 누릅니다.
    사용자 삽입 이미지

    추가된 Silverlight 페이지는 마찬가지로 마크업과 코드-비하인드로 구성되어 있으며 마크업의 루트 엘리먼트에서 정의한 x:Class 어트리뷰트와 동일한 이름의 클래스가 코드-비하인드에 정의되어 있습니다.

    이렇게 추가된 Silverlight 페이지는 하나의 HTML에서 관리할 수도 있지만 다른 HTML 페이지를 생성하여 HTML레벨에서 내비게이팅할 수도 있습니다. 만약 HTML 페이지를 임의로 추가한다면 템플릿이 만들어준 .html과 .js처럼 적절한 코드를 사용하여 Silverlight 페이지를 로드해야 하겠죠.

    Hello Silverlight!

    시작부터 동영상 플레이어!?
    보통 어떤 언어를 시작할 땐 항상 Hello, world 류의 텍스트 출력을 해보기 마련인데요, Silverlight이 얼마나 직관적으로 코드를 작성할 수 있는지 보여드리기 위해 곧바로 간단한 웹 동영상 플레이어를 만들어 보겠습니다. 흔히 백문이 불여일타라는 말을 많이 쓰지만 Silverlight은 정말로 그 효과가 크지요. 지금 바로 해보세요!

    Howto:1-3. 간단한 웹 동영상 플레이어 예제
    1. 새 Silverlight 프로젝트 생성합니다.
    2. 아래의 코드를 각각 입력합니다. (Page.xaml과 Page.xaml.cs)
    3. Ctrl+Shift+B 또는 F6을 눌러 빌드하고 F5를 눌러 실행합니다.

    Code:Page.xaml
    < Canvas x:Name="parentCanvas"
       
    xmlns="http://schemas.microsoft.com/client/2007"
       
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       
    Loaded="Page_Loaded"
       
    x:Class="SilverlightProject1.Page;assembly=ClientBin/SilverlightProject1.dll"
       
    Width="800"
       
    Height="600"
       
    Background="White"
       
    >
        <
    TextBlock Text="Hello Silverlight!" FontSize="30" />
        <
    MediaElement x:Name="moviePlayer" Width="800" Height="600" Source="Silverlight.wmv" AutoPlay="False" MediaEnded="OnMediaEnded" />
        <
    TextBlock Canvas.Left="0" Canvas.Top="620" Text="Play" MouseLeftButtonDown="OnPlay" />
        <
    TextBlock Canvas.Left="50" Canvas.Top="620" Text="Stop" MouseLeftButtonDown="OnStop" />
        <
    TextBlock Canvas.Left="100" Canvas.Top="620" Text="Pause" MouseLeftButtonDown="OnPause" />
    </
    Canvas>

    Code:Page.xaml.cs (코드 길이상 using 구문은 표시하지 않았습니다.)
    namespace SilverlightProject1
    {
        public partial class Page : Canvas
       
    {
       
        public void Page_Loaded(object o, EventArgs e)
            {
               
    // Required to initialize variables
               
    InitializeComponent();
            }

           
    void OnMediaEnded(object sender, EventArgs e)
            {
               
    // 미디어 플레이가 끝났을 때 Stop을 눌러 처음부터 재생할 수 있도록 합니다.
               
    moviePlayer.Stop();
            }

           
    void OnPlay(object sender, MouseEventArgs e)
            {
                moviePlayer.Play();
            }

           
    void OnStop(object sender, MouseEventArgs e)
            {
                moviePlayer.Stop();
            }

           
    void OnPause(object sender, MouseEventArgs e)
            {
                moviePlayer.Pause();
            }
        }
    }

    주요 코드의 구성
    상세한 코드를 보기 전에 마크업인 XAML과 코드-비하인드인 CS 코드 파일의 관계를 살펴보죠. XAML은 HTML과 같이 구성 요소 즉, 엘리먼트 들을 태그로 표현하고 태그 내의 어트리뷰트로 구성 요소들의 속성을 나타냅니다. 템플릿 구성에서 언급했던 것처럼 마크업의 루트 엘리먼트(여기에서는 Canvas)는 반드시 x:Class 어트리뷰트를 포함해야 하며, 코드-비하인드에서 바인딩할 클래스와 네임스페이스 및 어셈블리를 정의합니다.

    코드-비하인드를 살펴보면 x:Class 어트리뷰트에서 정의한대로 SilverlightProject1 이란 네임스페이스내에 Page 클래스를 정의하고 있습니다. x:Class 어트리뷰트의 정의 중에 assembly=ClientBin/SilverlightProject1.dll 이란 구문으로 어셈블리 경로를 지정하는데요, 여기서 지정된 어셈블리는 코드-비하인드가 컴파일 된 결과물입니다. 이것은 웹 사이트에 소스 코드를 배포하지 않고 오직 컴파일된 바이너리 파일만 있으면 된다는 걸 말합니다. 즉, 마크업에는 일반적인 UI 요소를 구성하고 공개되지만 내부적인 비지니스 로직은 코드-비하인드로 말 그대로 숨길 수 있다는 것을 의미합니다. 이 부분에 대해서는 아래에서 다시 얘기하겠습니다.

    상세한 코드를 보죠.
    루트 엘리먼트인 Canvas는 일종의 컨테이너로 다른 엘리먼트들을 포함합니다. Canvas내에는 TextBlock 엘리먼트를 사용하여 화면에 표시할 문자열을 지정하였고 MediaElement 엘리먼트를 사용해 동영상을 재생할 영역을 지정하였습니다. Orcas의 IDE에서 이 코드들을 입력할 경우 현재 상황에서 입력이 가능한 요소들만 인텔리센스로 표시되기 때문에 매우 경쾌하게 코딩할 수 있습니다.

    각 엘리먼트의 어트리뷰트들도 매우 직관적인 이름을 가지고 있어서 이 예제에서 사용된 것들은 굳이 설명이 필요 없을 정도입니다. 몇 가지 중요한 어트리뷰트들만 짚어보죠.

    모든 엘리먼트에 공통적으로 사용가능한 x:Name은 코드-비하인드에서 직접 사용할 수 있는 개체의 이름을 정의합니다. 엘리먼트의 이름을 지정함으로써 x:Class에서 정의한 클래스 내에서 멤버 변수처럼 사용할 수 있습니다. 다음 그림을 보면 마크업에서 정의한 x:Name으로 코드-비하인드에서 마치 멤버 변수인 것처럼 심지어 인텔리센스도 지원한다는 걸 확인할 수 있습니다.


    어트리뷰트로 이벤트 핸들러를 지정할 수도 있습니다. 예제에서 MediaElement의 MediaEnded와 TextBlock의 MouseLeftButtonDown이 바로 해당 이벤트에 대한 핸들러의 이름을 지정하고 있습니다. 이벤트 역시 매우 직관적인 이름인데요, MediaEnded는 미디어 재생이 끝났을 때를 의미하고 MouseLeftButtonDown은 마우스 왼쪽 버튼이 눌렸을 때를 말한다는 걸 설명할 필요는 없을 겁니다.

    이렇게 마크업에서 지정한 이벤트 핸들러는 코드-비하인드에서 반드시 구현해야 합니다. Silverlight에서 모든 엘리먼트의 이벤트는 두개의 파라미터로 전달되는데 여기에 대한 설명은 따로 좀 더 상세하게 알아보겠습니다.

    우선 예제를 살펴보면 어트리뷰트에서 지정한 이름과 일치하는 멤버 함수들을 볼 수 있습니다. 여기에서 해당 이벤트에 대한 비지니스 로직 코드를 구현하면 되는 거죠. 각 코드들 역시 따로 주석이 필요치 않을 정도로 간단하고 직관적입니다.
    주의
    MediaElement는 현재 동영상으로 WMV 포맷과 음악으로 MP3, WAV 포맷만을 지원합니다. 따라서 서비스 전에 필요한 파일을 인코딩할 필요가 있는데요, Microsoft는 이러한 인코딩을 위한 툴로 Expression MediaEncoder를 내놓았습니다. 현재 Preview 상태로 평가판을 180일간 사용할 수 있으니 미리 테스트 해보시는 것도 좋을 것 같네요. 이 외에도 전문적인 인코딩을 위한 서버 제품들도 준비되어 있는데 http://uxkorea.net/blog_post_54.aspx 이곳을 참고하시기 바랍니다.



    자동으로 생성되는 코드
    아마 예리하신 분이라면 Page 클래스 첫줄에 있는 Page_Loaded 멤버 함수와 InitializeComponent 메소드 호출을 눈여겨 봤을 겁니다. Page_Loaded는 Silverlight 페이지가 HTML에 로드될 때 발생하는 이벤트 핸들러로써 Silverlight.js에 의해 호출됩니다. 여기에서 이 클래스의 멤버 변수 등을 초기화할 수 있습니다.

    그런데, InitializeComponent 메소드는 어떤 역할일까요? 결론부터 말하자면 말 그대로 XAML 페이지에 있는 컴포넌트들을 초기화하는 메소드입니다. 그럼 이 메소드는 어디에서 정의되어 있을까요? 분명히 이 메소드는 프로젝트 내의 어디에도 보이지 않습니다. 혹시나 하고 부모 클래스인 Canvas 클래스를 뒤져봐도 이런 메소드는 정의되어있지 않습니다. 바로 이 메소드는 컴파일러가 자동으로 생성해주는 코드에서 구현되고 있습니다. 컴파일러는 마크업의 x:Class로 정의된 엘리먼트를 코드-비하인드에서 사용될 개체로 자동으로 생성하여 개발자의 귀찮은 코딩을 덜어주는 거죠. 이 코드는 obj\Release(또는 Debug) 폴더아래에 파일명.g.cs(또는 .vb)라는 이름으로 자동으로 생성됩니다. 이것은 XAML과 매니지드 코드와의 컴파일 과정에서 일어나는 일인데 전에 포스팅한 http://gongdo.tistory.com/74을 참고하세요. 이 글에서는 WPF의 컴파일에 대해 언급하지만 WPF와 Silverlight는 기본적인 구동 방식이 같으므로 이해하는데 문제가 없을 거라 생각합니다.

    배포하기

    Silverlight는 웹 기반 기술입니다. 물론 테스트는 로컬에서 하겠지만 제대로 하려면 웹서버 등을 갖춰야 하죠. 어쨌든 웹 상에서 작성한 Silverlight 애플리케이션의 배포는 단순히 .xaml.cs 등의 매니지드 코드로 작성한 소스 코드는 제외하고 컴파일된 어셈블리만 포함하면 됩니다. 위의 예제의 경우 예를 들어 http://gongdosoft.com/example 이란 URL로 배포하고 싶다면 다음과 같은 구조를 갖는게 일반적일 것입니다.
    Silverlight 배포 예제
    +WebRoot


    +Include


    -Silverlight.js


    +Example


    +ClientBin


    -SilverlightProject1.dll


    -Page.xaml


    -TestPage.html


    -TestPage.html.js


    -Silverlight인트로.wmv



    예제 코드에서는 Silverlight.js를 모든 다른 파일과 같은 장소에 둔 걸로 가정하였지만 위의 배포 예제에서는 좀 더 일반적인 방법으로 Silverlight.js를 최상위 Include 경로로 옮겨봤습니다. 물론 코드는 약간 수정을 해야겠죠.

    중요한 것은 중요한 비지니스 로직이 포함된 .cs 파일 즉, 코드-비하인드 파일은 포함하지 말고 컴파일된 어셈블리만을 포함하는 것입니다. 코드-비하인드는 말 그대로 숨겨두세요.

    참고

    개체 브라우저
    아직 Silverlight 1.1에 대한 MSDN 레퍼런스가 나와있지 않아서 어떤 클래스에 어떤 멤버들이 있는지 한눈에 보기 어렵습니다. 하지만 Silverlight의 개체들은 그 이름이 매우 설명적이기 때문에 개체 브라우저(Object Browser)에서 그 구성도를 보는 것 만으로도 클래스의 역할을 이해하는데 도움이 됩니다.
    림}
    Howto:1-4. 개체 브라우저 보는 방법
    1. 프로젝트를 연 상태에서 메뉴에서 View->Object Browser를 선택하거나 Ctrl+W,J를 누릅니다.
    2. 또는 우측의 솔루션 익스플로러의 Reference 항목에서 원하는 어셈블리를 더블 클릭합니다.

    레퍼런스 및 정보 찾기
    앞서 말한 것처럼 아직 Silverlight 1.1의 레퍼런스가 없으므로 Javascript 버전의 레퍼런스를 참고해야 합니다. 예를 들어 TextBlock에 대한 레퍼런스는 http://msdn2.microsoft.com/en-us/library/bb188394.aspx 에서 확인할 수 있습니다.

    비록 영문이고 Javascript 버전이긴 하지만 Silverlight에 대한 기초를 더 공부하고 싶다면 http://msdn2.microsoft.com/en-us/library/bb404770.aspx 여기를 참고하시길 바랍니다.

    역시 영문이지만 Silverlight 포럼도 도움이 된....다고 얘기드리고 싶지만 여긴 아직 검색도 안되네요. http://silverlight.net/forums/Default.aspx 네, 검색이 안되니 필요한 정보를 찾기가 좀 어렵습니다. 차라리 구글에서 검색하는게 훨씬 빠를지도 몰라요.

    계속해서 영문이지만(...) http://silverlight.net/blogs/silverlightcommunity/ 여기에 개발자들의 포스팅이 트랙백되고 있습니다.

    그리고! 바로 http://gongto.tistory.com 에서도 질문과 의견을 환영합니다!

    참고로 위의 예제 프로젝트를 첨부했으니 한번 테스트해보세요. 아무리 간단하더라도 남이 만든걸 테스트하는 것도 중요한 것 같아요.
    마지막으로 간단하게 만들어본 Silverlight 인트로 영상. 역시 못써먹을 것 같아서 올립니다. -_-


    http://gongdo.tistory.com/attachment/cfile23.uf@25763B455878F5540B571D.avi 여기서 다운로드도 가능해요.
    Posted by gongdo

    Unattended Windows XP DVD도 만들었겠다, 상쾌하게 윈도를 재설치하고 Orcas Beta1설치를 시작했습니다.

    시작부터 꼬이더니만 .Net Framework 3.5를 설치할 수 없다고 나오더군요.
    XP 무인설치 DVD에는 IE7, .Net Framework 1.1, 2, 3런타임 및 모든 보안패치가 적용되어있는 상태였기때문에 혹시 이 문제인가 싶어서 이것저것 지워보면서 수없이 설치 과정을 반복했는데요, 결국 범인은 미리 설치해둔 .Net Framework 2와 3 런타임이었네요. ㄱ-

    윈도 재설치하기 전엔 VS 2005와 .Net Framework 2, 3 모두 다 설치해놓고 쓰고 있었는데도 Orcas Beta1이 잘 설치되었었는데 새로 설치한 환경에선 무슨 이유에선지 반드시 설치된 닷넷 런타임을 제거해야만 되더군요.

    Orcas Installation Failed로 구글링해보시면 그 외에도 많은 설치 문제가 있음을 확인할 수 있어요. 혹시 Orcas Beta1 설치 도중 문제가 생긴다면 닷넷 2와 3 버전을 제거하고 시도해보세요.

    수시간 동안의 삽질 끝에 드디어 설치에 성공했습니다. Silverlight 개발을 위한 익스텐션들도 잘 설치해줬구요.
    윈도 설치하는 것보다 Orcas 설치하는데 시간이 훨씬 더 많이 들어가네요. OTL

    기대를 하고 Silverlight 새 프로젝트를 하나 만들어봤어요.


    RC1에 비해 크게 달라진 점은 없고 윈도를 재설치해서인지 로딩 속도랑 반응 속도가 조금씩 향상된 느낌이에요.

    Silverlight 프로젝트로 간단하게 끄적여봤어요.


    Silverlight 1.1 의외로 가벼운 것 같네요. 플래쉬는 페이지 리프레쉬때 상당한 부담을 느끼는데 Silverlight은 그런 느낌이 덜한것 같아요. 물론 더 복잡한 페이지를 만들어봐야 비교가 되겠지만요.

    이제 윈도 재설치도 했겠다 다시 한번 시작해봐야죠. 합!

    Posted by gongdo

    마이크로소프트가 최근(...이라기엔 좀 뒷북인 감이 있지만) 코드명 WPF/E를 Silverlight라는 정식 명칭으로 발표한건 관심있는 분들이라면 이미 알고 계실거에요.
    Silverlight... 마이크로소프트의 네이밍 센스는 나름 괜찮다고 생각했는데 요건 좀 발음하기가 왠지 부끄럽네요. 입에 잘 안붙을 것 같은 예감.-ㅅ-

    그건 그렇고.

    Silverlight와 플래쉬는 앞으로 서로 경쟁하게될 기술이죠.
    이 두 기술의 장점과 단점은 서로 극명하게 대치되는 것 같아요.
    가장 큰 차이는 성능/편의성과 보편성.
    기술에 있어서 성능과 범용성은 거의 대부분 반비례관계를 갖는것 처럼 이 두 기술이 그런 양상을 보여준다는게 재밌어요.
    요컨대, 플래쉬는 거의 대부분의 웹플랫폼에 포팅되어 사용된 만큼 압도적인 보급률을 자랑하지만 다양한 기종에 맞추다보니 소프트웨어 즉, CPU 성능에 의존하므로 특히 그래픽스 성능에 제한이 있겠고, Silverlight는 크로스플랫폼을 표방하고는 있지만 제한적인 플랫폼(심지어 같은 윈도 플랫폼에서도 XP SP2이상만 가능한) 만을 지원하지만 대신 OS와의 밀접한 관계로 VGA와 같은 하드웨어 가속의 성능을 이끌어 낼 수 있다는 거죠. 물론 플래쉬도 하드웨어 가속 지원 못할것도 없지만 다양한 플랫폼에 맞춰 호환되는 공통적인 수단을 제공한다는건 글쎄요, 쉽지 않을거에요.

    Silverlight에 대한 제 관심은 스위스 취리히 공항 데모와 같이 RIA를 잘 활용한 애플리케이션에 치중되어있었는데요, 아무래도 이 정도 수준의 잘동작하는 애플리케이션을 개발한다는건 기술적으로 상당한 부담내지는 진입장벽이 있을 것 같아요.

    하지만 누구씨 블로그에서 국내에서 곧바로 적용할 수 있을 만한 영역을 알게 되었어요. 바로 고화질 웹플레이어 시장인데, 아시다시피 최근 UCC가 마케팅 차원에서 유행하고 있잖아요? 너도나도 사용자가 동영상 올리기만하면 UCC네 하면서요...
    뭐 현상이야 어쨌든 요는 좀 더 편리하고 비용 효율적인 웹플레이어가 시장에서 요구되고 있다는 얘기가 되겠죠.

    기술적인 부담도 지금의 웹플레이어 수준의 애플리케이션이라면 클라이언트 쪽은 단 몇일만 예제를 따라해보고 수정해도 구현할 수 있으니 그렇게 크지 않아요. 그만큼 XAML이 미디어 기능에 대한 지원이 풍부하고 직관적이니까요. 게다가 서버쪽은 IIS와의 연동으로 별다른 어려움 없이 서비스할 수 있을테구요.

    이런 웹플레이어 시장은 제가 아는한 플래쉬 플레이어와 ActiveX 컨트롤로 구분되는데, 현재 플래쉬로 구현되어 있는 사이트보단 여전히 ActiveX 컨트롤을 쓰는 사이트에 더 매력적이지 않을까 해요. 단적으로 ActiveX 컨트롤에 대한 사용자의 거부감이 (적어도 제가 느끼기엔) 점점 더 커지는데다가 OS의 정책도 점점 ActiveX 컨트롤의 보안을 강화하니까 기술적으로도 귀찮은 점이 늘어나니까요.

    물론 플래쉬도 Silverlight도 ActiveX 컨트롤로 브라우저에 올라가지만 플래쉬야 선택이 아닌 필수가 되었고 Silverlight도 시간이 지나면 플래쉬와 비슷한 플러그인 정도로 인식이 되겠죠. 더군다나 MS가 마음만 먹으면 서비스팩이나 윈도 업데이트에 포함시켜버릴 수도 있겠구요. 어쨌든 어떤 사이트에서 배포하는 검증되지 않은 ActiveX 컨트롤 보다야 훨씬 믿을 수 있을거에요.

    하지만, 문제는 플랫폼 호환성.
    제가 얘기하고 싶은건 리눅스나 맥... 이런것까지도 아니고 윈도 플랫폼내에서의 문제에요.
    아마도 어떤 사이트를 운영해보고 이용자 통계를 내보면 윈도 계열에서 XP SP2 이하를 사용하는 사용자는 1%내외가 될거라고 생각하는데요, 이 정도면 그냥 무시해도 되겠거니... 싶은데 그렇지도 않나봐요.

    용산의 꽤 큰 쇼핑몰에서 근무하는 지인에게 만약 사이트를 개편하는데 사이트의 주요 페이지가 XP SP2 이상에서만 보여도 괜찮겠냐고 물어봤더니 '그래도 아직은...'이란 답이 나오더군요. 운영자 입장에서야 어떠 새로운 기술을 도입해서 사이트가 경쟁력을 갖게 되는 건 얼씨구나 좋은 일이겠지만 한편 1%정도지만 이 사용자들을 무시하는 것도 쉽게 결정할 수 없을 거에요.

    하물며 동영상 서비스라면 더 넓은 사용자 층을 가질텐데 이미 플래쉬 플레이어로 서비스를 구축해놨다면 Silverlight가 매력적일지라도 쉽게 이전을 결정하긴 어려울 것 같아요.
    그러나 ActiveX 컨트롤이라면 얘기가 약간 달라지는게 우선 윈도 계열 전용으로 확실히 제한되어 있으니 아직까지 XP SP2 이상에서만 지원된다는 점은 어쩌면 큰 문제가 안될 수도 있겠지요.

    이런 점들 때문에 Silverlight가 플래쉬로 구축된 곳보다는 ActiveX 컨트롤로 운영되는 동영상 서비스를 제공하는 사이트에 더 매력이 있다고 생각해요.


    제가 아는한, MS는 Silverlight를 XP SP2 이전 세대의 윈도에서 가능하도록 할 계획은 없다고 해요. 지금 Silverlight는 크로스플랫폼을 표방하면서 약간은 물타기하는 느낌도 드는데 이런 제약을 뚫고 궤도에 오를 수 있을지...

    Silverlight의 가능성은 바로 윈도 구버전을 지원하지 않는다는 작지만 치명적인 문제를 시장이 얼마나 빨리 수용하느냐에 달려있지 않을까요?
    그리고 그 열쇠는 Vista가 가지고 있구요. :)

    Posted by gongdo


    티스토리 툴바