본문 바로가기
개발/ASP.NET MVC

ASP.NET MVC Razor View Helper Extentions

by 그저그런보통사람 2011. 12. 18.
'@' 이를 이용한 Razor 문법을 이용하여 아이템 리스트 출력 때 발생하는 반복적인 foreach 문을 제거하고 디자인 영역을 자유롭게 표현하기 위해 delegate 문법을 이용한 확장 메소드입니다.

public static class RazorExtentions
{
        public static HelperResult List<T>(this IEnumerable<T> items, Func<T, HelperResult> tempalte)
        {
            return new HelperResult(writer =>
                                        {
                                            foreach (var item in items)
                                            {
                                                tempalte(item).WriteTo(writer);
                                            }
                                        });
}

public static HelperResult List<T>(this IEnumerable<T> items, Func<T, HelperResult> tempalte,
                                                Func<dynamic, HelperResult> nodata)
{
            if (items.Count() == 0)
                return new HelperResult(x => nodata(null).WriteTo(x));

            return List(items, tempalte);
}

* 출처에 기반해서 리스트 항목에 아이템이 존재하지 않을 경우 출력("아이템이 없습니다"와 같은...)할 기능을 추가함 (두번째 메소드).

아래와 같이 사용하면 됩니다.

@{
    ViewBag.Title = "Home Page";


    var items = new string[0];

    var comics = new[] {
                           new {Title = "Groo", Publisher = "Dark House Comics"},
                           new {Title = "Spiderman", Publisher = "marval"},
                           new {Title = "Batman", Publisher = "marvel"},
                       };

    var nodatas = new List<IDictionary<string, object>>(); // 빈 데이타 목록.

    var nodataMessage = "데이터가 존재하지 않습니다";    
}

1. 데이터가 존재하는 경우.

<table>
<tr>
    <th>코믹스 제목</th>
    <th>발행사</th>
</tr>
@comics.List(
    @<tr>
        <td>@item.Title</td>
        <td>@item.Publisher</td>
    </tr>
, @<tr>
    <td colspan="2">@nodataMessage
    </td>
</tr>)
</table>
 

2. 데이터가 존재하지 않는 경우. 
 
<table>
<tr>
    <th>코믹스 제목</th>
    <th>발행사</th>
</tr>
@nodatas.List(
    @<tr>
        <td>@item["a"]</td>
        <td>@item["b"]</td>
    </tr>, 
    @<tr>
        <td colspan="2">@nodataMessage</td>
    </tr>)
</table>






Partial View에서는 Layout에서 지정한 'Section' 기능을 사용하지 못합니다. 그래서 partial view에서 자바 스크립트를 작성하면 본문 중간에 배치되는 깔끔하지 못한 상황이 연출되는데 아래 확장 Helper 메소드를 이용하여 Layout 페이지에 스크립트를 배치시킬 수 있습니다.

원리는 간단합니다.

ScriptBlock() 을 원하는 partial view 에서 배치하고 파라미터로 script를 작성하면 WebViewPage 의 Context Item 중에 식별하기 위해 정의한 키를 기반으로 StringBuilder 개체를 가져오거나 생성합니다.
그리고 delegate 식으로 (여기서는 Func<dynamic, HelperResult>) 할당한 script 문장을 StringBuilder에 추가하고 이를 다시 Context.items에 추가합니다.
이때까지는 Context 에 추가된 상태라 출력이 되지 않습니다.

Layout 에 WriteScriptBlock() 를 원하는 위치에 배치 (보통 자바스크립트는 body 태그의 닫는 시점 바로 위에 위치)하면 Layout 페이지가 렌더링 되는 시점에 해당 메소드를 호출하여 앞 전에 추가해둔 StringBuilder 객체를 호출해 MvcHtmlString 개체로 할당하여 추가합니다.

이는 흡사 UI Control를 제어하는 것과 비슷합니다.(DropDownList() 등등)


private const string SCRIPT_BLOCK__BULIDER = "ScriptBlockBuilder";

public static MvcHtmlString ScriptBlock(this WebViewPage webPage, Func<dynamic, HelperResult> template)
{
            if (!webPage.IsAjax)
            {
                var scirptBuilder = webPage.Context.Items[SCRIPT_BLOCK__BULIDER] as StringBuilder
                                               ?? new StringBuilder();

                scirptBuilder.Append(template(null).ToHtmlString());

                webPage.Context.Items[SCRIPT_BLOCK__BULIDER] = scirptBuilder;

                return new MvcHtmlString(string.Empty);
            }

            return new MvcHtmlString(template(null).ToHtmlString());
 }

 public static MvcHtmlString WriteSciptBlock(this WebViewPage webPage)
 {
            var scriptBuilder = webPage.Context.Items[SCRIPT_BLOCK__BULIDER]
                                             as StringBuilder ?? new StringBuilder();

            return new MvcHtmlString(scriptBuilder.ToString());
        }
  }


#출처가 있는데 마구잡이 인터넷 서핑중에 발견한거라 까먹었네요. ㅡ,.ㅡ;;;