본문 바로가기

.Net/SharePoint 2013

[Sample Code] 멀티 탭 웹파트(Multi Tab WebPart) 구현

안녕하세요. 김승진입니다.

오늘은 간단한 탭형 웹파트의 샘플 코드를 공개하려 합니다.


보통 SharePoint 기반으로 포탈 구축을 하다보면 필수적으로 나오는 요구사항 중 하나가 탭형 웹파트입니다.

일반적으로 메인화면의 공간이 제한적이기 때문에 주요 게시판 즉 공지사항 같은 게시판을 중첩해서 메인화면에 배치하려는 요구사항이죠.


아래 화면과 같이 탭을 클릭 할 때 마다 다른 게시판에 내용을 보여 주는 것이죠.

조금 특이하다면 첫번째 최신 탭은 대상이 되는 게시판 중 최신 내용만 모아서 보여주는 가상 탭을 의미합니다.

아마 SharePoint 외에 국내 포탈/그룹웨어 솔루션에서는 기본 기능으로 많이 있는 기능입니다.


코드를 보기 전에 간단히 정리를 하자면 개념은 이렇습니다.

1. 탭형웹파트는 기존의 목록(List)을 활용한다.

2. 뷰(VIEW)를 확인하여 화면에 노출한다.

3. 첫번째 탭은 '최신' 탭으로 대상 목록(List) 중 최신 내용을 모아서 보여준다.

4. 툴파트(ToolPart)에서 '최신' 탭의 이용여부를 선택 할 수 있다.

5. 툴파트(ToolPart)에서 대상 목록(List) 를 지정 할 수 있다.

6. 툴파트(ToolPart)에서 목록(List)의 갯수를 지정 할 수 있다.

7. 대상 목록(List)의 컬럼(Column)은 다를 수 있으나 제목과 작성자, 작성일은, 수정자, 수정일은 필수로 존재해야 한다.

8. 논리적으로 탭의 최대 갯수는 제약을 두지 않는다.

9. 다국어를 위한 리소스 처리를 한다.


내용은 복잡하게 설명했으나 복잡할 것은 하나도 없습니다.


관심을 두셔야 할 파일의 목록입니다.

1. TabViewWebpart\TabViewWebPart.cs

2. TabViewWebpartToolpart.cs

3. MultiTabWebpart.ascx

4. MultiTabWebpart.ascx.cs


이중에서 핵심은 1, 4번 입니다.

나머지 모든 파일은 첨부 파일을 통해서 다운로드 받을 수 있습니다.

간단한 코드 이니 샘플 코드로 보고 이해하시기는 어려움이 없을 것 같습니다.

감사합니다.


1. TabViewWebpart\TabViewWebPart.cs 코드

using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using Microsoft.SharePoint.Utilities;
using System.Xml.Serialization;
using System.Collections.Generic;

namespace JINCROM.WebParts
{
    [ToolboxItemAttribute(false)]
    public class TabViewWebPart : Microsoft.SharePoint.WebPartPages.WebPart//System.Web.UI.WebControls.WebParts.WebPart
    {
        #region TabViewList - 탭에 보여줄 SharePoint View 정보
        //공지#URL#공지사항#모든 항목,문서#URL#일반문서#모든 항목
        //TabTitle#WebUrl#ListName#ViewName
        private string m_TabViewList = string.Empty;
        [Browsable(true),
        Category("JINCROM"),
        DefaultValue(""),
        WebPartStorage(Storage.Shared),
        FriendlyName("탭 목록"),
        Description("탭명#웹Url#리스트명#뷰명;")]
        public string TabViewList
        {
            get { return this.m_TabViewList; }
            set { this.m_TabViewList = value; }
        }
        #endregion

        #region IsUseLatestTab - 최신 탭 사용 여부
        private bool m_IsUseLatestTab = false;
        [Browsable(true),
        Category("JINCROM"),
        DefaultValue(false),
        WebPartStorage(Storage.Shared),
        FriendlyName("최신 탭 사용 여부"),
        Description("최신 탭 사용 여부")]
        public bool IsUseLatestTab
        {
            get { return this.m_IsUseLatestTab; }
            set { this.m_IsUseLatestTab = value; }
        }
        #endregion

        #region ViewColumnList - 컬럼 목록
        private string m_ViewColumnList = string.Empty;
        [Browsable(true),
        Category("JINCROM"),
        DefaultValue(""),
        WebPartStorage(Storage.Shared),
        FriendlyName("컬럼 목록"),
        Description("Title,Modified,...")]
        public string ViewColumnList
        {
            get { return this.m_ViewColumnList; }
            set { this.m_ViewColumnList = value; }
        }
        #endregion

        #region ItemRowLimit - 항목 갯수
        private int m_ItemRowLimit = 5;
        [Browsable(true),
        Category("JINCROM"),
        DefaultValue(5),
        WebPartStorage(Storage.Shared),
        FriendlyName("항목 갯수"),
        Description("항목 갯수")]
        public int ItemRowLimit
        {
            get { return this.m_ItemRowLimit; }
            set { this.m_ItemRowLimit = value; }
        }
        #endregion

        // Visual Studio might automatically update this path when you change the Visual Web Part project item.
        private const string _ascxPath = @"~/_CONTROLTEMPLATES/MultiTabWebPart.ascx";

        #region CreateChildControls
        protected override void CreateChildControls()
        {
            JINCROM.Controls.MultiTabWebPart m_MultiTabWebPart = (JINCROM.Controls.MultiTabWebPart)Page.LoadControl(_ascxPath);
            m_MultiTabWebPart.TabViewList = this.m_TabViewList;
            m_MultiTabWebPart.IsUseLatestTab = this.m_IsUseLatestTab;
            m_MultiTabWebPart.ViewColumnList = this.m_ViewColumnList;
            m_MultiTabWebPart.ItemRowLimit = this.m_ItemRowLimit;
            Controls.Add(m_MultiTabWebPart);
        }
        #endregion

        #region
        protected override void RenderWebPart(HtmlTextWriter output)
        {
            base.RenderWebPart(output);
        }
        #endregion

        #region GetToolParts
        /// 
        /// Override the get tool part
        /// 
        /// 
        public override ToolPart[] GetToolParts()
        {
            List _toolParts = new List(base.GetToolParts());
            _toolParts.Insert(0, new TabViewWebPartToolPart());
            return _toolParts.ToArray();
        }
        #endregion
    }
}

4. MultiTabWebpart.ascx.cs 코드

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Text;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint;
using System.Data;

namespace JINCROM.Controls
{
    /// 
    /// 탭형 웹파트
    /// 
    public partial class MultiTabWebPart : UserControl
    {
        #region Properties

        #region TabViewList - 탭에 보여줄 SharePoint View 정보
        //공지#URL#공지사항#모든 항목,문서#URL#일반문서#모든 항목
        //탭명#WebUrl#ListName#ViewName
        private string m_TabViewList = string.Empty;
        public string TabViewList
        {
            get { return this.m_TabViewList; }
            set { this.m_TabViewList = value; }
        }
        #endregion

        #region IsUseLatestTab - 최신 탭 사용 여부
        private bool m_IsUseLatestTab = false;
        public bool IsUseLatestTab
        {
            get { return this.m_IsUseLatestTab; }
            set { this.m_IsUseLatestTab = value; }
        }
        #endregion

        #region ViewColumnList - 컬럼 목록
        private string m_ViewColumnList = string.Empty;
        public string ViewColumnList
        {
            get { return this.m_ViewColumnList; }
            set { this.m_ViewColumnList = value; }
        }
        #endregion

        #region ItemRowLimit - 항목갯수
        private int m_ItemRowLimit = 5;
        public int ItemRowLimit
        {
            get { return this.m_ItemRowLimit; }
            set { this.m_ItemRowLimit = value; }
        }
        #endregion

        #endregion

        #region Page_Load
        /// 
        /// 페이지 로드
        /// 
        /// 
        /// 
        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                //Page.Response.Write(this.m_TabViewList + this.m_IsUseLatestTab + this.m_ViewColumnList + this.m_ItemRowLimit);

                //탭 목록을 페이지에 표시한다.
                this.ltrTabList.Text = this.GetTabHTML();

                if (!IsPostBack)
                {
                    //탭의 내용을 페이지에 표시한다.
                    this.ltrItemList.Text = this.GetItemDataList(-1);
                }
                
            }
            catch (Exception ex)
            {

            }
        }
        #endregion

        #region GetTabHTML
        /// 
        /// TabViewList에 등록된 값으로 Tab Html을 조합한다.
        /// 
        /// 
        private string GetTabHTML()
        {
            StringBuilder strbTabHTML = new StringBuilder();

            //등록한 TabViewList값이 있으면
            if (this.m_TabViewList.Split(',').Length > 1)
            {
                strbTabHTML.AppendFormat("");
                strbTabHTML.AppendFormat("");
                //최신 탭 사용여부를 선택했을 경우
                if (this.m_IsUseLatestTab)
                {
                    strbTabHTML.AppendFormat("  ");
                }

                for (int i = 0; i < this.m_TabViewList.Split(',').Length; i++)
                {
                    string strClassName = "link_taboff";
                    string strTabItemInfo = this.m_TabViewList.Split(',')[i];

                    if (i == 0 && !this.m_IsUseLatestTab)
                    {
                        strClassName = "link_tabon";
                    }

                    strbTabHTML.AppendFormat("  ");
                }

                strbTabHTML.AppendFormat("");
                strbTabHTML.AppendFormat("
", i, strClassName); strbTabHTML.AppendFormat(" ", i); strbTabHTML.AppendFormat(strTabItemInfo.Split('#')[0]); strbTabHTML.AppendFormat(" "); strbTabHTML.AppendFormat("
"); } return strbTabHTML.ToString(); } #endregion #region GetIteaDataList /// /// 선택한 Tab의 값으로 해당 탭의 아이템 목록을 HTML로 조합한다. /// /// private string GetItemDataList(int selectedTabIndex) { StringBuilder strbDataListHTML = new StringBuilder(); try { //최신 탭을 눌렀을 경우 또는 페이지가 로드 되었을 경우 if (selectedTabIndex == -1) { //최신 탭 사용 여부가 설정 되어 있다면 if (this.m_IsUseLatestTab) { DataTable dtTable = new DataTable(); //TabName 컬럼 추가 DataColumn dcTabNameColumn = new DataColumn("TabName"); dtTable.Columns.Add(dcTabNameColumn); //DefaultDisplayFormUrl 컬럼 추가 DataColumn dcDefaultDisplayFormUrl = new DataColumn("DefaultDisplayFormUrl"); dtTable.Columns.Add(dcDefaultDisplayFormUrl); //ID 컬럼 추가 DataColumn dcID = new DataColumn("ID"); dtTable.Columns.Add(dcID); //m_ViewColumnList만큼 컬럼 추가 for (int i = 0; i < this.m_ViewColumnList.Split(',').Length; i++) { DataColumn dcColumn = new DataColumn(this.m_ViewColumnList.Split(',')[i]); dtTable.Columns.Add(dcColumn); } //TabList 만큼 루프 for (int i = 0; i < this.m_TabViewList.Split(',').Length; i++) { string strTabName = this.m_TabViewList.Split(',')[i].Split('#')[0]; string strWebUrl = this.m_TabViewList.Split(',')[i].Split('#')[1]; string strListName = this.m_TabViewList.Split(',')[i].Split('#')[2]; string strViewName = this.m_TabViewList.Split(',')[i].Split('#')[3]; SPWeb spwWeb = new SPSite(string.Format("{0}{1}", System.Configuration.ConfigurationManager.AppSettings["RootSiteUrl"], strWebUrl)).OpenWeb(); SPList splList = spwWeb.Lists.TryGetList(strListName); SPView spvView = splList.Views[strViewName]; #region SPList 별 루프 //입력한 정보로 생성한 SPList가 있는 경우 if (splList != null) { SPListItemCollection splicItems = splList.GetItems(spvView); int nRowLimit = splicItems.Count > this.m_ItemRowLimit ? this.m_ItemRowLimit : splicItems.Count; #region SPListItem 별 루프 for (int j = 0; j < nRowLimit; j++) { DataRow drRow = dtTable.NewRow(); #region Column 별 루프 for (int k = 0; k < this.m_ViewColumnList.Split(',').Length; k++) { //Tab Prefix Name 추가 if (k == 0) { drRow[k] = strTabName; drRow[k + 1] = splList.DefaultDisplayFormUrl; drRow[k + 2] = splicItems[j].ID; } if (splList.Fields.ContainsField(this.m_ViewColumnList.Split(',')[k])) { SPField spfField = splList.Fields.GetField(this.m_ViewColumnList.Split(',')[k]); string strFieldValue = string.Empty; try { if (this.m_ViewColumnList.Split(',')[k].ToUpper() == "TITLE") { if (splicItems[j].File != null || splicItems[j].Folder != null) { strFieldValue = Convert.ToString(splicItems[j]["LinkFilename"]); } else { strFieldValue = Convert.ToString(splicItems[j][spfField.InternalName]); } } else { strFieldValue = Convert.ToString(splicItems[j][spfField.InternalName]); } } catch { } drRow[k + 3] = strFieldValue; } else { drRow[k + 3] = ""; } } #endregion dtTable.Rows.Add(drRow); } #endregion } #endregion } //수정된 날짜로 정렬 DataView dvDocList = dtTable.DefaultView; dvDocList.Sort = "Modified DESC"; DataTable dtRecentItemList = dvDocList.ToTable(); #region HTML 조합 strbDataListHTML.AppendFormat(""); int nRowCount = dtRecentItemList.Rows.Count > this.m_ItemRowLimit ? this.m_ItemRowLimit : dtRecentItemList.Rows.Count; for (int i = 0; i < nRowCount; i++) { strbDataListHTML.AppendFormat("", dtRecentItemList.Rows[i]["DefaultDisplayFormUrl"], dtRecentItemList.Rows[i]["ID"]); for (int j = 0; j < this.m_ViewColumnList.Split(',').Length; j++) { //0일때 TabName 추가 if (j == 0) { strbDataListHTML.Append(""); } strbDataListHTML.Append(""); } strbDataListHTML.Append(""); } strbDataListHTML.Append("
"); strbDataListHTML.Append(dtRecentItemList.Rows[i]["TabName"]); strbDataListHTML.Append(""); strbDataListHTML.Append(dtRecentItemList.Rows[i][this.m_ViewColumnList.Split(',')[j]]); strbDataListHTML.Append("
"); #endregion } else { //권한이 없는 사용자가 있을 수 있으므로 권한 상승하여 문서 유형을 조회한다. SPSecurity.RunWithElevatedPrivileges(delegate() { string strWebUrl = this.m_TabViewList.Split(',')[0].Split('#')[1]; string strListName = this.m_TabViewList.Split(',')[0].Split('#')[2]; string strViewName = this.m_TabViewList.Split(',')[0].Split('#')[3]; SPWeb spwWeb = new SPSite(string.Format("{0}{1}", System.Configuration.ConfigurationManager.AppSettings["RootSiteUrl"], strWebUrl)).OpenWeb(); SPList splList = spwWeb.Lists.TryGetList(strListName); SPView spvView = splList.Views[strViewName]; //입력한 정보로 생성한 SPList가 있는 경우 if (splList != null) { strbDataListHTML.AppendFormat(""); SPListItemCollection splicItems = splList.GetItems(spvView); int nRowLimit = splicItems.Count > this.m_ItemRowLimit ? this.m_ItemRowLimit : splicItems.Count; for (int i = 0; i < nRowLimit; i++) { strbDataListHTML.AppendFormat("", splList.DefaultDisplayFormUrl, splicItems[i].ID); for (int j = 0; j < spvView.ViewFields.Count; j++) { strbDataListHTML.Append(""); } strbDataListHTML.Append(""); } strbDataListHTML.Append("
"); strbDataListHTML.Append(splicItems[i].GetFormattedValue(spvView.ViewFields[j])); strbDataListHTML.Append("
"); //strbDataListHTML.Append(spvView.RenderAsHtml(false, false, "")); } }); } } //각 탭을 눌렀을 경우 else { //권한이 없는 사용자가 있을 수 있으므로 권한 상승하여 문서 유형을 조회한다. SPSecurity.RunWithElevatedPrivileges(delegate() { string strWebUrl = this.m_TabViewList.Split(',')[selectedTabIndex].Split('#')[1]; string strListName = this.m_TabViewList.Split(',')[selectedTabIndex].Split('#')[2]; string strViewName = this.m_TabViewList.Split(',')[selectedTabIndex].Split('#')[3]; SPWeb spwWeb = new SPSite(string.Format("{0}{1}", System.Configuration.ConfigurationManager.AppSettings["RootSiteUrl"], strWebUrl)).OpenWeb(); SPList splList = spwWeb.Lists.TryGetList(strListName); SPView spvView = splList.Views[strViewName]; //입력한 정보로 생성한 SPList가 있는 경우 if (splList != null) { strbDataListHTML.AppendFormat(""); SPListItemCollection splicItems = splList.GetItems(spvView); int nRowLimit = splicItems.Count > this.m_ItemRowLimit ? this.m_ItemRowLimit : splicItems.Count; for (int i = 0; i < nRowLimit; i++) { strbDataListHTML.AppendFormat("", splList.DefaultDisplayFormUrl, splicItems[i].ID); for (int j = 0; j < spvView.ViewFields.Count; j++) { strbDataListHTML.Append(""); } strbDataListHTML.Append(""); } strbDataListHTML.Append("
"); strbDataListHTML.Append(splicItems[i].GetFormattedValue(spvView.ViewFields[j])); strbDataListHTML.Append("
"); } }); } } catch(Exception ex) { strbDataListHTML.Remove(0, strbDataListHTML.Length); strbDataListHTML.AppendFormat("{0}", ex.ToString()); } return strbDataListHTML.ToString(); } #endregion protected void upnlWebPartContent_Load(object sender, EventArgs e) { string strSelectedTabIndex = this.hhdSelectedTabIndex.Value; if (!string.IsNullOrEmpty(strSelectedTabIndex)) { this.ltrItemList.Text = this.GetItemDataList(Convert.ToInt32(strSelectedTabIndex)); } } } }