메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

IT/모바일

ASP.NET 가이드 3. UI 향상 및 사용자 템플릿 만들기

한빛미디어

|

2005-05-03

|

by HANBIT

15,404

저자: 한동훈(traxacun)

[지난 기사 보기]
ASP.NET 가이드 1. 자바 스크립트 사용하기
ASP.NET 가이드 2. 숫자/문자 입력 텍스트 박스 만들기

이번 시간에는 UI 향상을 위해서 몇 가지 자바 스크립트를 더 추가해서 BasePage의 기능을 향상시켜보자.

긁어가기 금지

마우스로 사용자들이 컨텐트를 긁어갈 수 있는데, 이런 긁어가기를 못하게 하는 것이다. 이것은 익히 알고 있는 것처럼 IE에만 적용된다. BODY 태그에 다음과 같은 내용을 추가하면 긁어가기나 소스 보기를 위해 마우스 오른쪽 버튼을 사용하는 것을 못하게 할 수 있다.

mmlt;body onContextMenu="return false" onDragStart="return false" onSelectStart="return false"mmgt;

그러나, 매번 새로운 웹 폼을 추가할 때마다 위와 같은 작업을 반복하는 것은 시간낭비다. BasePage에서 BODY 태그에 위와 같은 내용을 자동으로 추가하게 하는 것은 어떨까?



[그림1] DisableMouseDragging() 구현

DisableMouseDragging() 함수는 BasePage_PreRender()에서 호출하도록 한다.

    protected void BasePage_PreRender( object sender, System.EventArgs e )
    {
      RegisterClientScript();
      DisableMouseDragging();
    }

다양한 자바 스크립트 등록은 RegisterClientScript()에서 하고, 마우스 드래깅은 DisableMouseDragging()에서 처리하고 있다.

BODY 태그와 같이 웹 컨트롤로 지정되어 있지 않는 컨트롤은 모두 HtmlGenericControl로 사용할 수 있다. 다만, 이렇게 하기 위해서는 ASPX 페이지의 BODY 태그에 runat=server id=body를 추가해야 한다.



[그림2] BODY 태그

이제, 점점 강력해지는 BasePage를 보면서 사용해보고 싶다는 생각이 들더라도, 웹 폼을 추가할 때마다 BODY 태그를 수정해야하고, System.Web.UI.Page를 Mona.Web.UI.BasePage로 변경하는 작업을 반복하는 것은 참을 수 없을 것이다. 이를 해결할 수 있는 방법은 없을까? 답은 나만의 VS.NET 템플릿 페이지를 작성하는 것이다.

Mona WebPage 템플릿 작성

웹 폼을 추가할 때 자동으로 생성되는 ASPX와 ASPX.CS 페이지는

C:\Program Files
\Microsoft Visual Studio .NET 2003
\VC#
    \VC#Wizards
    \CSharpAddWebFormWiz
       \Templates
       \1042

에 있는 파일들이다.
Templates\1042에 있는 WebForm1.aspx 파일을 수정하면 여러분의 입맛대로 기본 페이지를 만들 수 있다. 다만, 직접 변경하는 것이 두렵다면 CSharpAddWebFormWiz 폴더를 모두 복사 & 붙여넣기한다. 그러면 "사본 - CSharpAddWebFormWiz" 폴더가 생성된다.



[그림3] VC#Wizard 폴더

복사한 폴더의 이름을 CSharpAddMonaWebFormWiz로 변경한다. Templates\1042 폴더에 있는 WebForm1.aspx 파일을 열어 BODY 태그를 다음과 같이 변경한다. [!output ]은 VS.NET에서 동적으로 코드를 채우기 위해 쓰는 코드이므로 신경쓰지 않아도 된다. 원한다면 MS_POSITIONING="FlowLayout"으로 바꿔도 상관없다.



수정한 템플릿을 VS.NET에서도 나타나게 해야 하는데 이는 VC#\CSharpProjectItems에 있는 CSharpAddWebFormWiz.vsz을 수정해야 한다.



[그림4] VS.NET 파일 추가 마법사 파일들

이 파일을 복사해서 CSharpAddMonaWebFormWiz.vsz으로 이름을 변경하고 다음 부분을 수정한다.



[그림5] CSharpAddMonaWebFormWiz.vsz 편집

여기까지 했으면 기본적인 마법사 코드는 모두 추가된 것이다. 다음은 VS.NET에서 새항목 추가를 눌렀을 때 실제로 Mona WebForm 항목이 화면에 보이도록 만드는 부분이다. 이 부분을 위해서는 다음 파일들을 수정해야 한다.



[그림6] WebProjectItems.vsdir

그림6의 디렉터리 구조는 VS.NET에서 새 항목 추가에서 보는 대화상자의 구조와 동일하다. 즉, VS.NET에서 추가할 아이템 항목을 보여주는 부분은 이곳에서 구성한다. WebProjectItems.vsdir은 전체를 선택했을 때 나타나는 UI 목록을 관리하는 파일이며, WebProjectItems\UI\ui.vsdir 파일은 UI를 선택했을 때 보여줄 목록을 관리하는 파일이다.
먼저 WebProjectItems.vsdir을 다음과 같이 편집한다.



[그림7] WebProjectItems.vsdir 편집

첫번째는 WebForm을 위한 것이며, 두번째는 이를 그대로 복사해서 CSharpAddMonaWebFormWiz.vsz으로 변경하고, #2236 대신 Mona WebForm이라 입력한 것이다. 마찬가지로 UI\ui.vsdir 파일도 위와 같이 동일하게 수정하면 된다.



[그림8] ui.vsdir 편집

이제 VS.NET에서 새 항목을 추가할 때마다 Mona WebForm이 나타나고 이를 이용하면 ASPX 페이지를 매번 수정하지 않아도 된다.



[그림9] Mona WebForm 템플릿을 추가한 화면

그러나 아직 ASPX.CS 코드를 수정하는 부분을 다루지 않았다. 이 부분은 생각보다 상당히 복잡하다.

웹 폼을 추가할 때 작성되는 코드는 VC#\DesignerTemplates\1042에 있는 NewWebFormCode.cs지만, ASPX 페이지를 추가할 때처럼 이 파일을 복사하는 것만으로는 변경이 되지 않는다. - VS 2005에서는 이러한 부분이 보다 단순하게 변경되었으며, 이에 대해서는 뒤에 다루도록 하겠다.

Building a Custom Web Form Wizard in Visual Studio.NET1)에 인용되어 있는 코드를 이용해야 한다.

VC#\VC#Wizards\CSharpAddMonaWebFormWiz\Templates\1042 폴더에서 Templates.inf 파일을 다음과 같이 편집한다.



[그림10] Templates.inf 수정

다음은 Templates\1042 폴더에 WebForm1.aspx.cs 파일을 작성하는 것이다.



[그림11] WebForm1.aspx.cs

위에서 볼 수 있는 것처럼 WebForm1.aspx.cs에 using 문을 추가했고, Mona.Web.UI.BasePage 클래스를 기본 상속하게 만들었다.

다음은 VC#Wizards\CSharpAddMonaWebFormWiz\Scripts\1042 폴더의 default.js를 변경하는 것이다.

1.// (c) 2001 Microsoft Corporation
2. function AddDefaultServerScriptToWizard(selProj)
3. {
4.    wizard.AddSymbol("DEFAULT_SERVER_SCRIPT", "JavaScript");
5. }
6.
7. function AddDefaultClientScriptToWizard(selProj)
8. {
9.    var prjScriptLang = selProj.Properties("DefaultClientScript").Value;
10.    // 0 = JScript
11.    // 1 = VBScript
12.    if(prjScriptLang == 0)
13.    {
14.         wizard.AddSymbol("DEFAULT_CLIENT_SCRIPT", "JavaScript");
15.    }
16.    else
17.    {
18.         wizard.AddSymbol("DEFAULT_CLIENT_SCRIPT", "VBScript");
19.    }
20. }
21.
22. function AddDefaultDefaultHTMLPageLayoutToWizard(selProj)
23. {
24.    var prjPageLayout = selProj.Properties("DefaultHTMLPageLayout").Value;
25.    // 0 = FlowLayout
26.    // 1 = GridLayout
27.    if(prjPageLayout == 0)
28.    {
29.         wizard.AddSymbol("DEFAULT_HTML_LAYOUT", "FlowLayout");
30.    }
31.    else
32.    {
33.         wizard.AddSymbol("DEFAULT_HTML_LAYOUT", "GridLayout");
34.    }
35. }
36.
37. function OnFinish(selProj, selObj)
38. {
39.    var oldSuppressUIValue = true;
40.    try
41.    {
42.         oldSuppressUIValue = dte.SuppressUI;
43.       var strProjectName      = wizard.FindSymbol("PROJECT_NAME");
44.       var strSafeProjectName = CreateSafeName(strProjectName);
45.       wizard.AddSymbol("SAFE_PROJECT_NAME", strSafeProjectName);
46.       SetTargetFullPath(selObj);
47.       var strProjectPath      = wizard.FindSymbol("TARGET_FULLPATH");
48.       var strTemplatePath      = wizard.FindSymbol("TEMPLATES_PATH");
49.
50.       var strTpl = "";
51.       var strName = "";
52.       var InfFile = CreateInfFile();
53.      
54.       // add the default project props for the aspx file before we
55.       // render it
56.       AddDefaultServerScriptToWizard(selProj);
57.       AddDefaultClientScriptToWizard(selProj);
58.       AddDefaultTargetSchemaToWizard(selProj);
59.       AddDefaultDefaultHTMLPageLayoutToWizard(selProj);
60.      
61.       // render our file
62.       AddFilesToProject(selObj, strProjectName,
63.               strProjectPath, InfFile, true);
64.      
65.       AddReferencesForWebForm(selProj);
66.    }
67.    catch(e)
68.    {
69.       if( e.description.length > 0 )
70.          SetErrorInfo(e);
71.       return e.number;
72.    }
73.    finally
74.    {
75.          dte.SuppressUI = oldSuppressUIValue;
76.          if( InfFile )
77.          InfFile.Delete();
78.    }
79. }
80.
81. // Make sure that the names of the files mentioned here match with
    // that physically present in the folder
82. function SetFileProperties(oFileItem, strFileName)
83. {
84.    if(strFileName == "WebForm1.aspx")
85.    {
86.         oFileItem.Properties("SubType").Value = "Form";
87.    }
88.   
89.    if(strFileName == "WebForm1.aspx.cs")
90.    {
91.         oFileItem.Properties("SubType").Value = "Code";
92.    }
93. }
94.
95. function AddFilesToProject(oProj, strProjectName,
96.      strProjectPath, InfFile, AddItemFile)
97. {
98.    try
99.    {
100.       dte.SuppressUI = false;
101.       var projItems;
102.
103.            projItems = oProj;
104.
105.       var strTemplatePath = wizard.FindSymbol("TEMPLATES_PATH");
106.
107.       var strTpl = "";
108.       var strName = "";
109.
110.       // if( Not a web project )
111.       if(strProjectPath.charAt(strProjectPath.length - 1) != "\\")
112.          strProjectPath += "\\";   
113.
114.       var strTextStream = InfFile.OpenAsTextStream(1, -2);
115.       while (!strTextStream.AtEndOfStream)
116.       {
117.          strTpl = strTextStream.ReadLine();
118.          if (strTpl != "")
119.          {
120.             strName = strTpl;
121.             var strType = "";
122.             if (strName == "WebForm1.aspx")
123.             {
124.                strType = "Form";
125.             }
126.             else // this would be code-behind file
127.             {
128.                strType = "Code";
129.             }
130.            
131.             var strTarget = "";
132.             var strFile = "";
133.             strTarget = wizard.FindSymbol("ITEM_NAME");
134.            
135.             //if we are adding the code
136.                         //behind file, we need to append
137.                         //the .CS extension
138.             //to the name obtained from the
139.                         //Add New Item dialog. this name would be
140.             //something like "webform2.aspx"
141.             if(strType == "Code")
142.             {
143.                strTarget = strTarget + ".cs";
144.             }
145.
146.             var fso;
147.             fso = new
148.                           ActiveXObject("Scripting.FileSystemObject");
149.             var TemporaryFolder = 2;
150.             var tfolder = fso.GetSpecialFolder(TemporaryFolder);
151.             var strTempFolder =
152.                            fso.GetAbsolutePathName(tfolder.Path);
153.
154.             var strFile = strTempFolder + "\\" +
155.                           fso.GetTempName();
156.             //var strFile = strTempFolder + "\\" + strTarget;
157.
158.             var strClassName = strTarget.split(".");
159.             wizard.AddSymbol("SAFE_CLASS_NAME", strClassName[0]);
160.                wizard.AddSymbol("SAFE_ITEM_NAME", strClassName[0]);
161.
162.             var strTemplate = strTemplatePath + "\\" + strTpl;
163.             var bCopyOnly = false;
164.             var strExt = strTpl.substr(strTpl.lastIndexOf("."));
165.             if(strExt==".bmp" || strExt==".ico" ||
166.                           strExt==".gif" || strExt==".rtf"
167.                           || strExt==".css")
168.                bCopyOnly = true;
169.             wizard.RenderTemplate(strTemplate,
170.                           strFile, bCopyOnly, true);
171.
172.             var projfile =
173.                            projItems.AddFromTemplate(strFile, strTarget);
174.             SafeDeleteFile(fso, strFile);
175.            
176.             if(projfile)
177.                SetFileProperties(projfile, strName);
178.
179.             if(strType == "Form")
180.             {
181.                var window = projfile.Open(vsViewKindPrimary);
182.                window.visible = true;
183.             }
184.            
185.             //when adding the webform.aspx,
186.                         //the AddFromTemplate function called above
187.             //automatically also adds the code-behind file.
188.                         //Since we want to add our file
189.             //we will have to delete the file that
190.                         //was created by default before we
191.             //create our custom code-behind file
192.             if(strType == "Form")
193.             {
194.                var strTargetCS = strProjectPath
195.                               + strTarget + ".cs";
196.                SafeDeleteFile(fso, strTargetCS)
197.             }
198.          }
199.       }
200.       strTextStream.Close();
201.    }
202.    catch(e)
203.    {
204.       strTextStream.Close();
205.       throw e;
206.    }
207. }

이제 default.js 파일까지 수정을 했으면 완전한 Mona WebForm 템플릿을 작성한 것이다.

VS 2005의 사용자 템플릿

VS 2005는 아직 베타 단계에 있기 때문에 이에 대해서 얘기하기는 아직 이른듯하다. 실제로 VS 2005 CTP Feb만 살펴보아도 VC++의 템플릿 구조는 VS.NET 2003과 같은 구조를 따르지만 C#/VB.NET/J#은 전혀 다른 구조를 갖고 있다.

C:\Program Files
\Microsoft Visual Studio 8
\Common7
    \IDE
      \ItemTemplatesCache
       \Web\CSharp\1033\WebForm.zip

실제로는 \IDE\ItemTemplates에 각 템플릿이 압축파일로 되어 있고, 이에 대한 캐시는 압축 파일명을 디렉터리로 한 곳에 저장되어 있다. - VS 2005에서 아이템을 추가하면 캐시 페이지에서 불러온다.

그런가하면 각 vsdir 페이지는 C:\Program Files\Microsoft Visual Studio 8\Web\WebProjectItems 에 지정되어 있어서 템플릿에 대한 내용들이 특정 디렉터리가 아니라 이곳저곳에 마구 흩어져 있는 상황이다. 때문에 베타 단계에서 사용자 템플릿을 추가해도 변경될 가능성이 크기 때문에 여기서는 일단 다루지 않겠다. 다만, 시작점을 알려주었으니 관심있는 분들은 위 폴더에서 탐험해보기 바란다.

[참고자료]
1) Building a Custom Web Form Wizard in Visual Studio .NET
이 글은 VS.NET 2002를 기준으로 작성된 것이며, 여기에 VS.NET 2003을 위한 노트가 표시되어 있다.
TAG :
댓글 입력
자료실

최근 본 책0