아들래미와의 간만의 휴식..

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (7/26/2010 11:21:35 AM) Viewing : 3264

OutBack에 가서 식사를 했습니다..

빨리 달라고 보채네요...

식당에서

 

제 옷 하나 사러 Mall 에 갔는데 어린이용 선글라스를 팔더라구요..

하나 사주었습니다..(장모님이 계산을..ㅡ.ㅡ;)

이뿌다 이뿌다 하니까..귀찮은듯 해도 곧잘 착용하고 있네요...

지석이


마지막 업데이트 : (7/26/2010 11:21:35 AM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (2)
psj932님의 글 (7/26/2010 11:26:24 AM)
귀엾다야~~ ^^
아빠는안닮은것같어....ㅋㅋ
그래도 반갑네~~ 잘크고 있고만~!!



이방은님의 글 (7/26/2010 11:48:06 AM)
헐...
좋은 뜻이지???



댓글 쓰기

학대 받는 강아지...

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (4/29/2010 11:00:43 AM) Viewing : 5288

이게 로봇 강아지이니까 망정이지..ㅡ.ㅡ;

완전 개잡듯이..(??) 잡네요..ㅋ

 

Get Microsoft Silverlight


마지막 업데이트 : (4/29/2010 2:24:40 PM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기

우리 아들 지석이 돌 잔치 동영상입니다.

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (4/23/2010 7:06:28 PM) Viewing : 5255

돌잔치를 그러니까 2009년 10월에 했지요..

아빠가 되어서 너무나 게으른 나머지..이제서야 올리네요..

행여 제 아들래미 보고 싶으셨던 분들..(벗들..ㅎㅎㅎ)

감상하세요..

참고로 이거 10만원 짜리입니다..그럼..^^;

 

Get Microsoft Silverlight


마지막 업데이트 : (4/29/2010 10:58:04 AM)

TAG : 없음



Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기

AJAX History

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (9/2/2008 2:42:17 PM) Viewing : 5537

.NET Framwork 3.5 SP 1에 추가된 내용중에 하나인 AJAX History 에 대해서 살펴 보도록 하겠다.

이놈의 기능에 대해서 언급을 하자면. 
브라우저에서 앞으로/뒤로 버튼에 대한 히스토리를 저장해 보겠다 라는 취지이다.

일반적으로 브라우저의 캐싱은 (다들 아시겠지만 앞으로/뒤로버튼은 캐싱된 페이지를 불어 오는 것이다.) 페이지 기반이다.
페이지 기반이라고 말하는 것은 현재페이지에서 어떤 작업이나 행위를 하더라도 페이지의 변화가 없으면 뒤로 버튼을 클릭했을때 이전 작업 혹은 행위가 아니라 이전 페이지로 이동됨을 말한다.

이것은 앵커라고 불려지는 URL 상에 # 마커로 지정되어 페이지내에 구간 이동을 할 수있도록 만들어 놓은 태그를 이용한 방식이다. 테스트를 해보면 알겠지만 히스토리에 추가할 때 URL에 보게 되면 #키=값 형식으로 쿼리스트링뒤에 추가가 된다.
서버스크립트와 클라이언트스크립트간의 약간의 차이가 있긴 하지만 원리는 이와 같다고 볼 수 있다.

전체 코드는 여기(.NET Framework 3.5 Enhancements Training Kit) 에서 다운 받을 수 있으며 코드 외에 ppt와 문서들도 많이 있으니 각자 다운로드를 받아 테스트를 해 보기를 권한다.

 Client-Side History

첨부된 파일을 다운 받거나 위 링크에서 전체본을 다운 받아 실행을 해 보도록 하자.
서버나 클라이언트나 마찬가지로 AJAX History를 사용하기 위해서는

<asp:ScriptManager ID="scriptManager" runat="server" EnableHistory="true" />

위와 같이 ScriptManager의 EnableHistory 속성에 true를 설정해 주어야 한다..기본값은 false 이다.


ClientSideHistory.ascx 파일을 살펴 보자.

<asp:ScriptManagerProxy ID="ScriptManagerProxy1" runat="server">

    <Scripts>

        <asp:ScriptReference Path="~/Scripts/Default.js" />

    </Scripts>

</asp:ScriptManagerProxy>

<div>

    <h2>Client-Side</h2>

    <ul id="rating-list">

        <li>Baseball</li>

        <li>Basketball</li>

        <li>Boxing</li>

        <li>Cricket</li>

        <li>Football</li>

        <li>Golf</li>

        <li>Hockey</li>

        <li>NASCAR</li>

        <li>Rugby</li>

        <li>Soccer</li>

    </ul>

</div>

Default.js 파일을 잠조 하는 것을 볼 수있다.
이제 js파일에서 rating-list 라는 컨트롤의 click 이벤트를 통해 어떠한 작업을 하는 지 살펴보자.

    1 /// <reference name="MicrosoftAjax.js" />

    2 

    3 var ratingItems;

    4 

    5 Sys.Application.add_navigate(function(sender, args) {

    6 

    7     var value = args._state["Selected"];

    8     value = args.get_state().Selected;

    9     selectRating(value);

   10 });

   11 

   12 Sys.Application.add_load(function()

   13 {

   14 

   15     ratingItems = $get("rating-list").getElementsByTagName("li");

   16 

   17     for (var i = 0; i < ratingItems.length; i++)

   18     {

   19         $addHandler(ratingItems[i], "click", ratingClicked);

   20     }

   21 });

   22 

   23 function ratingClicked(e) {

   24 

   25     var value = e.target.innerHTML;

   26     Sys.Application.addHistoryPoint({ Selected: value }, "Selected: " + value);

   27     selectRating(value);

   28 }

   29 

   30 function selectRating(value)

   31 {

   32     for (var i = 0; i < ratingItems.length; i++)

   33     {

   34         var element = ratingItems[i];

   35 

   36         if (element.innerHTML == value)

   37         {

   38             Sys.UI.DomElement.addCssClass(element, "selected");

   39         }

   40         else

   41         {

   42             Sys.UI.DomElement.removeCssClass(element, "selected");

   43         }

   44     }

   45 }

load이벤트(12행)에서 click 이벤트 핸들러를 등록하고 ratingClicked 라는 델리게이트메서드를 콜 하는 것을 볼 수 있다.
23행의 ratingClicked 메서드는 HistoryPoint 라는 메서드를 호출하고 selectRating이라는 메서드를 호출한다.
먼저 selectRating이라는 메서드는 클릭한 개체에 이미지를 보여주는 스타일을 추가하는 메서드이며 26행의 addHistoryPoint 라는 메서드가 우리가 주목할 메서드이다.
이 메서드는 SP1에 새로 생긴 메서드이며 History에 추가하는 기능을 하는 메서드이다.
2개의 매개변수를 받는데 첫번째 메서드는 키/값 쌍이며 2번째 매개변수는 처음에 언급했던 Url 윈도에 보여질 타이틀 영역이다.
위의 예로 보아 Selected 라는 키를 가지며 값이 예를 들어 "bangsil"이라면 url윈도에는 Selected:bangsil 로 나오게 될것을 추측 할 수 있다.
이는 내부적으로 값에 대한 유효성을 검증한 후에 state 라는 컬렉션 변수에 순서대로 저장된다.
이제 저장이 되었다면 이것을 사용하는 법을 알아볼 차례다.
5행의 navigate 라는 이벤트는 브라우저의 앞으로/뒤로 버튼을 클릭했을때 발생되는 이벤트이다.
이 이벤트의 매개변수 args는 _state와 get_state() 라는 속성과 메서드를 갖는다.
즉 7행과 8행은 같은 작용을 하게 된다.
value에 값을 할당하고 다시 selectRating메서드를 호출하면 의도한 대로 이전에 클릭했던 아이템에 스타일이 먹히면서 이전 상태로 복원된다.

Server-Side History

이제 서버쪽으로 알아 보자.

ServerSideHistory.ascx 파일을 살펴 보자.

<div>

    <h2>Server-side</h2>

    <asp:UpdatePanel runat="server">

        <ContentTemplate>

            <asp:BulletedList ID="ratingBulletedList" runat="server" DisplayMode="LinkButton">

                <asp:ListItem Text="Baseball" />

                <asp:ListItem Text="Basketball" />

                <asp:ListItem Text="Boxing" />

                <asp:ListItem Text="Cricket" />

                <asp:ListItem Text="Football" />

                <asp:ListItem Text="Golf" />

                <asp:ListItem Text="Hockey" />

                <asp:ListItem Text="NASCAR" />

                <asp:ListItem Text="Rugby" />

                <asp:ListItem Text="Soccer" />

            </asp:BulletedList>

        </ContentTemplate>

    </asp:UpdatePanel>

</div>

UpdatePanel을 사용하였으며 내부에 BulletedList 라는 서버 컨트롤이 존재한다.

    1 public partial class ServerSideHistory : System.Web.UI.UserControl

    2 {

    3     protected override void OnInit(EventArgs e)

    4     {

    5         ratingBulletedList.Click += this.ratingBulletedList_Click;

    6         this.ScriptManager.Navigate += new EventHandler<HistoryEventArgs>(ScriptManager_Navigate);

    7         base.OnInit(e);

    8     }

    9 

   10     void ScriptManager_Navigate(object sender, HistoryEventArgs e)

   11     {

   12         this.SelectRating(e.State["Selected"]);

   13     }

   14 

   15     void ratingBulletedList_Click(object sender, BulletedListEventArgs e)

   16     {

   17         string value = ratingBulletedList.Items[e.Index].Text;

   18         this.ScriptManager.AddHistoryPoint("Selected", value);

   19         SelectRating(value);

   20     }

   21 

   22     void SelectRating(string value)

   23     {

   24         foreach (ListItem item in ratingBulletedList.Items)

   25         {

   26             if (item.Text == value)

   27                 item.Attributes["class"] = "selected";

   28             else if (item.Attributes["class"] != null)

   29                 item.Attributes.Remove("class");

   30         }

   31     }

   32 

   33     private ScriptManager ScriptManager

   34     {

   35         get

   36         {

   37             return ScriptManager.GetCurrent(Page);

   38         }

   39     }

   40 }

스크립트와 마찬가지로 3행을 보면 OnInit이벤트에 서버컨트롤의 클릭이벤트 등록과 더불어 ScriptManager의 Navigete 이벤트를 등록했음을 볼 수 있다.
15행의 클릭 이벤트 메서드를 보게 되면 역시 스크립트와 마찬가지로 SelectRating() 메서드를 호출하고 AddHistoryPoint() 메서드를 호출한다.
SelectRating() 메서드는 역시 클릭된 컨트롤의 스타일을 할당하는 코드가 들어 있고 주목해야 하는 AddHistoryPoint()메서드는 역시 똑같이 2개의 매개변수에 Selected라는 키와 value 를 가지고 있다.
10행의 Navigate 이벤트메서드를 보면 HistoryEventArgs의 State라는 NameValueCollection형의 속성을 통해 해당 value를 가져와 SelectRating메서드를 호출 하는 것을 볼 수 있다.

서버측과 클라이언트측을 같이 동작시켜보면서 url 윈도를 살펴보면 차이점을 금방 알 수 있다.
서버측을 실행하면 키와 값이 모두 암호화가 되어 전송되며 클라이언트측을 실행하면 url창에 그대로 키와 값이 보여지게 된다.
그러므로 키값이 같더라도 서버측과 클라이언트측을 동시에 사용할 수 있다.(별의미는 없어보이지만....)

정말 오랜만에 쓰는 글이어서..적응하기도 쉽지 않다..ㅡ.ㅡ;;;
이제 시작은 하였으니..절반은 한셈인가....@.@


마지막 업데이트 : (9/2/2008 3:13:47 PM)

TAG : 없음



첨부 파일 보기 (1)
Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기

리소스(resources)를 통합 관리 해보자.

현재 주소 복사
트랙백 주소 복사
방실이님의 글 (8/19/2008 10:43:15 AM) Viewing : 5716

리소스는 참 관리 하기 어려운 존재이다.

기본 적으로 VS 에서는 하나의 어셈블리마다 각각의 리소스를 사용할 수 있으며 파일명을 가지고 culture를 구분하여 동적으로 런타임시에 해당 리소스를 바인딩 하는 형식이 되겠다.

그러나 하나의 솔루션에 속하는 프로젝트가 많아 지다 보면 각각의 프로젝트에 속한 리소스를 관리하기가 여간...만만치않다.

나도 역시 이 문제 때문에 고민을 하다가 약간은 조잡할지 모르나 나름구성을 해보았다.

먼저 사용할 리소스의 형태는 확장자가 resX인 XML 형태와, 확장자가 resources 인 바이너리형태 , 2가지가 있다.
리소스를 작성하기 위해서는 IDE에 내장되어 있는 리소스 편집기를 이용하여도 상관 없으나 따로 Resourcer.NET 이라는 무료 도구를 이용하도록 하겠다.
사용법은 간단하니..pass 하도록 하겠다.

샘플프로젝트구조

샘플 프로젝트의 구조는 다음과 같다.
먼저 리소스를 관리할 BIT.TM.Resources 라는 프로젝트가 있다. 이 프로젝트에는 Proxies 라는 폴더와 Resources 라는 폴더가 있는데 관심있게 살펴 봐야 한다.
이 리소스를 사용할 프로젝트는 Sample 이라는 프로젝트이다. 
일반적으로 리소스는 그것을 사용할 프로젝트에 같이 있어야 하나, 분리를 시켜 독자적으로 관리 하게끔 하였다.
Proxies 라는 폴더와 Resources 라는 폴더에 있는 파일의 네이밍규칙을 살펴 보자.

이 리소스를 사용할 프로젝트의 네임스페이스를 사용하고 있다.
즉  문자열 리소스의 경우 Proxies 클래스의 네이밍룰은 {네임스페이스}.StringProxy.cs 가 되며, 
리소스의 경우 {네임스페이스}.String.{CultureCode(생략가능)}.resources 가 된다.

서두에 언급하였지만 리소스의 형식은 resX가 되었던 resources 가 되었던 상관은 없다.

자.. 이제 코드를 살펴 보자..
먼저 ResourceType 열거형을 살펴 보자.

    ///

    /// 리소스의 타입 열거형 Ver 1.0

    ///

    ///

    /// 2007.12.11 - Prototype - 이방은(http://www.bangsil.net)

    ///

    public enum ResourceType

    {

        ///

        /// 아이콘 타입입니다.

        ///

        Icon,

        ///

        /// 문자열 타입입니다.

        ///

        String,

        ///

        /// 이미지 타입입니다.

        ///

        Image

    }

리소스의 형식을 정의하는 열거형이다.
이제 리소스 파일을 읽어 관리하는 ResourceManager 를 살펴 보자.

   34 public CustomResourceManager(ResourceType resourceType, Type type)

   35 {

   36     bool hasResource = false;

   37     Assembly asm = Assembly.GetCallingAssembly();

   38     string resourceName = this.GetType().Namespace + ".Resources." + type.Namespace + "." + resourceType.ToString();

   39     foreach (string reName in asm.GetManifestResourceNames())

   40     {

   41         if (reName.Substring(0,reName.LastIndexOf('.')) == resourceName)

   42         {

   43             hasResource = true;

   44             break;

   45         }

   46     }

   47     if (!hasResource)

   48     {

   49         throw new MissingManifestResourceException("해당 타입의 리소스를 찾을 수 없습니다.");

   50     }

   51     else

   52     {

   53         rm = new ResourceManager(resourceName, asm);

   54     }

   55 }

생성자를 보게 되면 앞서 정의한 ResourceType열거형과 Type 개체를 받는걸 볼수 있다.
38행을 보게 되면 매개변수로 받은 type 변수로 호출할 어셈블리의 네임스페이스를 알아내고 이를 이용해 리소스 이름을 생성하는 것을 볼 수 있다.

그외 메서드로는

  104 ///

  105 /// 해당 키를 가지고 있는 문자열 타입의 리소스를 반환합니다.

  106 ///

  107 /// 리소스를 호출 할 키입니다.

  108 /// 반환되는 리소스입니다.

  109 internal string GetString(string key)

  110 {

  111     if (key.Length == 0)

  112     {

  113         return null;

  114     }

  115     try

  116     {

  117         return rm.GetString(key);

  118     }

  119     catch

  120     {

  121         return null;

  122     }

  123 }

과 같은 리소스의 값을 반환하는 메서드가 존재한다.

이제 Proxies 개체를 만들어 보도록 하겠다.

    7 namespace Sample

    8 {

    9     ///

   10     /// 문자열 리소스 Proxy 클래스 Ver 1.0

   11     ///

   12     /// 2007.12.11 - Prototype - 이방은(http://www.bangsil.net)

   13     public class StringProxy

   14     {

   15         private static CustomResourceManager rm;

   16

   17         ///

   18         /// 클래스의 정적 생성자입니다.

   19         ///

   20         static StringProxy()

   21         {

   22             rm = new CustomResourceManager(ResourceType.String, typeof(StringProxy));

   23         }

   24

   25         public static string TestString

   26         {

   27             get { return rm.GetString("TestString"); }

   28         }

   29     }

   30 }

주의 할 것은 이 프락시 클래스의 네임스페이스이다.
네임스페이스를 보게 되면 이 클래스가 존재하는 어셈블리의 이름(BIT.TM.Resources)이 아니고 이 클래스를 사용할 어셈블리의 네임스페이스가 등록된다.
그리고 정적 생성자에서 조금 전에 설명했던 CustomResourceManager 개체를 만들고 호출할 리소스의 키를 Property로 제공하기만 하면 된다.

이미지 프락시의 경우는 아래와 같다.

    8 namespace Sample

    9 {

   10     public class ImageProxy

   11     {

   12         private static CustomResourceManager rm;

   13

   14         ///

   15         /// 클래스의 정적 생성자입니다.

   16         ///

   17         static ImageProxy()

   18         {

   19             rm = new CustomResourceManager(ResourceType.Image, typeof(ImageProxy));

   20         }

   21

   22         public static Image TestImage

   23         {

   24             get { return rm.GetImage("TestImage"); }

   25         }

   26     }

   27 }

자 이제 리소스는 모두 정의 되어 있으니 이것을 사용하는 코드만 남았다.

Sample 프로젝트는 비즈니스계층으로 이 리소스를 사용하는 곳이 되겠다.

    8     public class Sample

    9     {

   10         public static string GetString()

   11         {

   12             return StringProxy.TestString;

   13         }

   14

   15         public static Image GetImage()

   16         {

   17             return ImageProxy.TestImage;

   18         }

   19     }

간단하게 위 처럼 정의해 보았다.
이제 이 개체를 Culture를 변경시켜 보여주도록 하기위에 폼단에서 코드를 손을 본다.

   19 private void Form1_Load(object sender, EventArgs e)

   20 {

   21     this.label4.Text = Sample.Sample.GetString();

   22     this.pictureBox1.Image = Sample.Sample.GetImage();

   23

   24     Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("en");

   25     this.label3.Text = Sample.Sample.GetString();

   26 }

20행과 21행은 한글버전이므로 
Sample.String.resources와 Sample.Image.resources 파을일 읽게 될 것이며
24행의 Culture변환으로 인해
25행의 경우에는 영문버전이 되므로
Sample.String.en.resources를 읽게 된다. 
그 결과는 아래와 같다.

실행결과

나름대로 짱구를 굴려 보았지만..현재까지는 이정도가 한계인듯 하다.
리소스 관리에 대해 더 좋은 의견이 있다면 
언제든 환영........


마지막 업데이트 : (9/15/2010 2:41:56 PM)

TAG : 리소스 resource 



첨부 파일 보기 (1)
Trackback 보기 (0)
댓글 보기 (0)
댓글 쓰기