처음에는 쓸 필요가 없을 듯 하여...(귀찮기도 하지만..ㅡ.ㅡ;) 패스 할려고 했으나..
몇몇분들의 요청이 있어서..
현재 사이트에서 사용중인 TreeView 메뉴에 대한 강좌를 시작하도록 하겠다..^^;
먼저 TreeView를 써 보신 분들은 아시겠지만...
Sitemap 을 이용해서 하게 되면..상당히 골치 아프다..ㅡ.ㅡ;
그래서 나의 경우에는 커스텀으로 xml을 만들어서 메뉴로 이용한다..
물론 TreeView가 아니어도 상관없다...
일반적인 사이트에서 메뉴의 특징을 살펴 보자.
- 거의 변하지 않는다...
- 카테고리마다 Left Menu가 변한다.
- Role에 의해 Visible 속성이 변할 수 있다.
이 세가지는 거의 모든 사이트에서 이용되는 방법이라 볼수 있겠다.
이러한 경우에 XML을 이용하면 참으로 편리하다..
각 카테고리마다 UserControl을 만들어서 사용했었던 개발자가 있다면..아래 방법으로 변경을 시도해 보는 것도 좋을듯 싶다...
아래 xml은 이 사이트에서 사용되는 메뉴에 대한 xml 이다.
<?xml version="1.0" encoding="utf-8" ?>
<Menu>
<Category url="/default.aspx" title="처음으로" description="첫 페이지로 이동합니다.">
</Category>
<Category url="/AboutMe.aspx" title="쥔장은.." description="저는 누구일까요??">
<Item url="/AboutMe.aspx" title="쥔장 소개" description="쥔장 소개입니다." />
<Item url="/board/list.aspx?BoardId=31185279-904C-4BA3-9752-B3F2EA62BC37" title="쥔장 낙서장" description="쥔장이 맘대로 끄적거린 글입니다." />
</Category>
<Category url="/board/list.aspx?BoardId=93a58900-87e8-4ed1-9cb9-a66ecb43ad59" title="게시판" description="게시판 입니다.">
<Item url="/board/list.aspx?BoardId=93a58900-87e8-4ed1-9cb9-a66ecb43ad59" title="알리는 글" description="알리는 글입니다." />
<Item url="/Board/List.aspx?BoardId=CA4E4AF3-083F-4D79-8079-CD42C674A57F" title="개발 히스토리" description="개발 히스토리입니다." />
<Item url="/Board/List.aspx?BoardId=ef3aa07e-6662-4670-8037-f89bba2d48a1" title="Microsoft 소식" description="마이크로소프트 소식입니다." />
<Item url="/board/list.aspx?BoardId=C783FA2B-AF07-4D26-9E15-B835DB541E6A" title="자유 게시판" description="아무나 글을 쓰셔도 됩니다." />
<Item url="/Board/List.aspx?BoardId=5a26d48c-a176-4130-9636-4fb07dfc565a" title="질문 게시판" description="질문을 올려 주세요." />
<Item url="/Board/List.aspx?BoardId=5f6a2c27-54a2-45f8-aab1-a6bfc567e550" title="사진 게시판" description="사진 게시판입니다." />
<Item url="/Board/List.aspx?BoardId=e37e600b-b769-4171-a655-09f4f776408e" title="커플 게시판" description="커플 게시판입니다." roles="Couple" />
</Category>
<Category url="/Board/List.aspx?BoardId=da05ba1b-3e9b-4d16-b8f8-ff2e4f7514c5" title="Article" description="아티클 입니다.">
<Item url="/Board/List.aspx?BoardId=6cb920b1-f969-499c-a79b-f3b285eb437d" title="퍼온글들" description="퍼온 글들입니다." />
<Item url="/Board/List.aspx?BoardId=da05ba1b-3e9b-4d16-b8f8-ff2e4f7514c5" title="쥔장글들" description="제가 쓴 글들입니다." />
<Item url="/Board/List.aspx?BoardId=a905689f-c7d4-410c-a7b2-98f822b9b0ba" title="Source Files" description="홈페이지 소스파일입니다." />
</Category>
<Category url="/Board/List.aspx?BoardId=bc974687-f70c-4aa9-8e90-ce201898b16f" title="자료실" description="자료실 입니다.">
<Item url="/Board/List.aspx?BoardId=bc974687-f70c-4aa9-8e90-ce201898b16f" title="공개 자료실" description="공개 자료실 입니다." />
<Item url="/Board/List.aspx?BoardId=66e51564-6372-4ddb-9d4e-28a21346191d" title="Back Up" description="비밀 자료실" roles="Admin" />
</Category>
<Category url="/visit.aspx" title="방명록" description="방명록을 남겨 주세요.">
</Category>
</Menu>
구성을 살펴 보면 Menu라는 최상단 노드가 있으며 이 노드는 Category 라는 자식 노드를 가지고 있다.
Category 라는 노드는 url , title, description 이라는 어트리뷰트를 가지고 있다.
그리고 자식노드로 Item 이라는 노드를 가지고 있다..
이 Item 이라는 노드는 url, title, description, roles 라는 노드를 가지고 있다.
Category라는 노드는 메뉴상에서의 하나의 카테고리가 된다..
이 사이트의 경우에는 게시판, article, 자료실, 방명록 등이 되겠다.
그리고 Item이라는 노드는 그 하위 메뉴가 된다..
많약에 Depth가 하나 더 필요 하다면 노드를 하나 더 만들면 되겠다.
여기서 중요한 어트리뷰트는 url과 roles가 되겠다.
url 의 경우에는 클릭했을때 이동할 페이지의 url이 되며 roles의 경우에는 해당 메뉴에 액세스가 가능한 역할이 되겠다.
이쯤으로 xml 파일 설명을 마치고 이제 이것을 읽어오는 부분을 살펴 보자.
MenuItem 이라는 클래스는 xml에서 Item 노드에 대한 클래스이다.
MenuCategory 라는 클래스는 xml에서 Category 노드에 대한 클래스가 되겠다.
이 클래스는 Items 라는 MenuItem 클래스의 컬렉션을 속성으로 가지고 있으며 Add 라는 메서드로 이 컬렉션에 MenuItem 개체를 넣을 수 있다.
단순한 속성의 열거이니 코드는 생략한다...
이제 XmlLoader 라는 클래스에 주목하자 ..
이 클래스는 xml을 읽어 와서 MenuCategory 라는 클래스를 만드는 역할을 하게 되겠다.
1 public static List<MenuCategory> LoadMenu()
2 {
3 List<MenuCategory> menu;
4 Cache cache = HttpContext.Current.Cache;
5
6 if (cache["Menu"] == null)
7 {
8 menu = new List<MenuCategory>();
9 XmlLoader.ReadMenuXml(menu);
10 cache.Insert("Menu", menu, null, System.Web.Caching.Cache.NoAbsoluteExpiration, new TimeSpan(0, 10, 0));
11 }
12 else
13 {
14 menu = (List<MenuCategory>)cache["Menu"];
15 }
16
17 return menu;
18 }
먼저 LoadMenu라는 메서드를 살펴 보자.
이 메서드는 외부노출(public) 한 유일한 메서드이다.
이 메서드는 캐시를 조사해서 캐시되지 않았으면 새로 캐시하고 캐시된게 있으면 캐시된 개체를 반환하는 역할을 한다.
맨 처음 언급했지만 메뉴는 거의..변할 일이 없다..그러므로 캐시를 사용토록 한다.(4행)
캐시가 소멸되었을 경우에만 새로 xml 파일을 읽도록 한다.(6행)
9행의 ReadMenuXml 메서드를 이용해 체를 만들고 10행 처럼 캐시한다.
이제 ReadMenuXml 메서드를 살펴 보자.
1 private static void ReadMenuXml(List<MenuCategory> menu)
2 {
3 XmlReader reader = XmlReader.Create(HttpContext.Current.Server.MapPath("~/Menu.xml"));
4 lock (reader)
5 {
6 while (reader.Read())
7 {
8 if (reader.IsStartElement("Category"))
9 {
10 MenuCategory category = new MenuCategory();
11 category.Title = String.IsNullOrEmpty(reader.GetAttribute("title")) ? "" : reader.GetAttribute("title");
12 category.Url = String.IsNullOrEmpty(reader.GetAttribute("url")) ? "" : reader.GetAttribute("url").ToLower();
13 category.Description = String.IsNullOrEmpty(reader.GetAttribute("description")) ? "" : reader.GetAttribute("description").ToLower();
14 category.Roles = String.IsNullOrEmpty(reader.GetAttribute("roles")) ? "*" : reader.GetAttribute("roles");
15
16 if (reader.ReadToDescendant("Item"))
17 {
18 do
19 {
20 MenuItem item = new MenuItem();
21 item.Title = String.IsNullOrEmpty(reader.GetAttribute("title")) ? "" : reader.GetAttribute("title");
22 item.Url = String.IsNullOrEmpty(reader.GetAttribute("url")) ? "" : reader.GetAttribute("url").ToLower();
23 item.Description = String.IsNullOrEmpty(reader.GetAttribute("description")) ? "" : reader.GetAttribute("description").ToLower();
24 item.Roles = String.IsNullOrEmpty(reader.GetAttribute("roles")) ? "*" : reader.GetAttribute("roles");
25 category.Add(item);
26 }
27 while (reader.ReadToNextSibling("Item"));
28 }
29
30 menu.Add(category);
31 }
32 }
33 }
34 }
3행에서 Xml 파일을 읽어서 XmlReader 개체를 만든다.
그리고 노드를 탐색 하면서 MenuCategory 개체와 Item 개체를 생성하고 List
자 이제 이렇게 생성된 List
LeftMenu 라는 유저 컨트롤을 만들고 그 안에 코딩하면 되겠다.
1 private void BindMenu()
2 {
3 List<MenuCategory> menu = XmlLoader.LoadMenu();
4 foreach (MenuCategory category in menu)
5 {
6 TreeNode parent = new TreeNode(category.Title, "", "/Image/category.gif", category.Url, "");
7 this.TreeView1.Nodes.Add(parent);
8 foreach (MenuItem item in category.Items)
9 {
10 if (item.Roles == "*" || Roles.IsUserInRole(item.Roles))
11 {
12 TreeNode child = new TreeNode(item.Title, "", "/Image/item.gif", item.Url, "");
13 parent.ChildNodes.Add(child);
14 }
15 }
16 }
17 }
이 BindMenu라는 메서드만 유저 컨트롤에서 호출하면 된다..
먼저 TreeView1이라는 트리뷰 컨트롤을 하나 생성했다.
XmlLoader.LoadMenu() 메서드로 List
이제 이 리스트를 루프 돌면서 하나씩 Add 해 주면 되겠다.
단지 10행에 보면 역할에 따라 Add 할것인지 말것인지 결정하는 부분이 있다.
Roles 라는 클래스는 RoleProvider를 구현해야지 사용할 수 있는 클래스이다.
10행의 조건문은 해당 Role이 없으면 화면에 렌더시키지 않게끔 하는 코드가 되겠다.
이제 왼쪽과 같은 트리뷰 메뉴를 볼 수 있을 것이다..
참고-- 실무에서는 트리뷰보다는 아마도 이미지라든지 플래시 같은 경우를 많이 쓸듯 한데..
이러한 체계가 이해가 된다면 응용하는 것은 쉽다...
메뉴 구성에 있어서 더 좋은 방법이 있거나 사용하고 있다면...조언 부탁..^^;