Click here to Skip to main content
13,095,663 members (55,008 online)
Click here to Skip to main content
Articles » Web Development » ASP.NET » General » Downloads

Stats

106.1K views
2.6K downloads
121 bookmarked
Posted 6 Nov 2007

Implementing Model-View-Presenter in ASP.NET

, 17 Nov 2007
Three implementations of Model-View-Presenter in ASP.NET 2.0.
MVP.SampleApp
Lib
Microsoft.Practices.EnterpriseLibrary.Common.dll
Microsoft.Practices.EnterpriseLibrary.Data.dll
MySql.Data.dll
nunit.framework.dll
Rhino.Mocks.dll
Model
Data
Interfaces
Properties
Presentation
Presentation.Tests
Properties
Interfaces
Properties
SubSonic
ActiveRecord
Builder
CodeGeneration
Templates
CodeLanguage
Configuration
Controls
Calendar
lang
skin
active-bg.gif
calendar.gif
dark-bg.gif
hover-bg.gif
menuarrow.gif
normal-bg.gif
rowhover-bg.gif
status-bg.gif
title-bg.gif
today-bg.gif
Resources
DataProviders
Properties
Sql Tools
SubSonic.snk
Sugar
WebApp
App_Data
Views
SQL2000SampleDb.msi
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using System.Web.UI.HtmlControls;
using System.Collections;

namespace SubSonic
{
    [DefaultProperty("TableName")]
    [ToolboxData("<{0}:QuickTable runat=server></{0}:QuickTable>")]
    public class QuickTable : WebControl, INamingContainer
    {
        #region props

        private bool showSort = true;
        public bool ShowSort
        {
            get { return showSort; }
            set { showSort = value; }
        }

        private string columnList = string.Empty;
        public string ColumnList
        {
            get { return columnList; }
            set { columnList = value; }
        }

        private string providerName = string.Empty;
        public string ProviderName
        {
            get
            {
                if(String.IsNullOrEmpty(providerName))
                {
                    providerName = DataService.Provider.Name;
                }
                return providerName;
            }
            set { providerName = value; }
        }

        private string tableName = string.Empty;
        public string TableName
        {
            get { return tableName; }
            set { tableName = value; }
        }

        private int pageSize;
        public int PageSize
        {
            get { return pageSize; }
            set { pageSize = value; }
        }

        private int pageIndex = 1;
        public int PageIndex
        {
            get { return pageIndex; }
            set { pageIndex = value; }
        }

        private string linkToPage = string.Empty;
        public string LinkToPage
        {
            get { return linkToPage; }
            set { linkToPage = value; }
        }

        private string linkOnColumn = string.Empty;
        public string LinkOnColumn
        {
            get { return linkOnColumn; }
            set { linkOnColumn = value; }
        }

        private List<Where> whereCollection;
        public List<Where> WhereCollection
        {
            get { return whereCollection; }
            set { whereCollection = value; }
        }

        private string whereExpression = string.Empty;
        public string WhereExpression
        {
            get { return whereExpression; }
            set { whereExpression = value; }
        }

        private string headerLinkCSSClass = string.Empty;
        private string headerLinkStyle = "text-decoration:none;color:black;font-size:12pt;font-family:arial;";
        public string HeaderLinkCSSClass
        {
            get { return headerLinkCSSClass; }
            set { headerLinkCSSClass = value; }
        }

        private string tableCSSClass = string.Empty;
        private string tableStyle = string.Empty;
        public string TableCSSClass
        {
            get { return tableCSSClass; }
            set { tableCSSClass = value; }
        }

        private string tableHeaderCSSClass = string.Empty;
        private string tableHeaderStyle = "font-weight:bold; text-align:center;font-family:arial;font-size:12pt;border-bottom:1px solid #666666;";
        public string TableHeaderCSSClass
        {
            get { return tableHeaderCSSClass; }
            set { tableHeaderCSSClass = value; }
        }

        private string tableCellCSSClass = string.Empty;
        private string tableCellStyle = "padding:3px;background-color:white;font-family:arial;font-size:10pt;";
        public string TableCellCSSClass
        {
            get { return tableCellCSSClass; }
            set { tableCellCSSClass = value; }
        }

        private string tableAlternatingCSSClass = string.Empty;
        private string tableAlternatingStyle = "padding:3px;background-color:whitesmoke;font-family:arial;font-size:10pt;";
        public string TableAlternatingCSSClass
        {
            get { return tableAlternatingCSSClass; }
            set { tableAlternatingCSSClass = value; }
        }


        private string pagerCSS = string.Empty;
        private string pagerStyle = "alignment:center; font-size:10pt;font-family:arial;border-top:1px solid #666666;margin-top:5px";
        public string PagerCSS
        {
            get { return pagerCSS; }
            set { pagerCSS = value; }
        }

        private string pagerButtonCSS = string.Empty;
        //give it some flare... why not :)
        private string pagerButtonStyle = "border:1px solid #cccccc;background-color:whitesmoke;font-family:helvetica;font-size:10pt";
        public string PageButtonCSSClass
        {
            get { return pagerButtonCSS; }
            set { pagerButtonCSS = value; }
        }

        private int totalRecords;
        public int TotalRecords
        {
            get { return totalRecords; }
            set { totalRecords = value; }
        }

        private int totalPages;
        public int TotalPages
        {
            get { return totalPages; }
            set { totalPages = value; }
        }

        private string buttonFirstText = " << ";
        public string ButtonFirstText
        {
            get { return buttonFirstText; }
            set { buttonFirstText = value; }
        }

        private string buttonPreviousText = " < ";
        public string ButtonPreviousText
        {
            get { return buttonPreviousText; }
            set { buttonPreviousText = value; }
        }

        private string buttonNextText = " > ";
        public string ButtonNextText
        {
            get { return buttonNextText; }
            set { buttonNextText = value; }
        }

        private string buttonLastText = " >> ";
        public string ButtonLastText
        {
            get { return buttonLastText; }
            set { buttonLastText = value; }
        }

        #endregion

        //The "wrapper" table that holds the data
        //and the pager
        private HtmlTable tblWrap = new HtmlTable();
        private HtmlTableRow trTop = new HtmlTableRow();
        private HtmlTableRow trBottom = new HtmlTableRow();
        private HtmlTableCell tdTop = new HtmlTableCell();
        private HtmlTableCell tdBottom = new HtmlTableCell();

        //the actual table that shows the output
        private HtmlTable tbl = new HtmlTable();


        //general purpose use
        private HtmlTableRow tr;
        private HtmlTableCell td;
        private TableSchema.Table schema;
        private ArrayList colList = new ArrayList();
        private DataTable dataSource;

        //the pager bits
        private HtmlTable tblPage = new HtmlTable();
        private Button btnFirst = new Button();
        private Button btnLast = new Button();
        private Button btnNext = new Button();
        private Button btnPrev = new Button();
        private DropDownList ddlPages = new DropDownList();
        private Label lblRecordCount = new Label();
        private Literal litPagerLabel = new Literal();

        private string sortBy;
        private const string SORT_BY = "sortBy";
        private const string TOTAL_RECORDS = "totalRecords";

        public string SortBy
        {
            get { return sortBy; }
            set { sortBy = value; }
        }

        private string sortDirection = "ASC";

        public string SortDirection
        {
            get { return sortDirection; }
            set { sortDirection = value; }
        }


        private void AddHeaderText(TableSchema.TableColumn col, HtmlTableCell tdHeaderCell, string overrideText)
        {
            if(showSort)
            {
                LinkButton btn = new LinkButton();
                btn.ID = "btn" + col.ColumnName;
                btn.CommandArgument = col.ColumnName;

                btn.Text = String.IsNullOrEmpty(overrideText) ? col.DisplayName : overrideText;

                if(!String.IsNullOrEmpty(headerLinkCSSClass))
                {
                    btn.CssClass = headerLinkCSSClass;
                }
                else
                {
                    btn.Attributes.Add("style", headerLinkStyle);
                }


                tdHeaderCell.Controls.Add(btn);

                if(col.IsNumeric)
                {
                    tdHeaderCell.Align = "right";
                }
                else if(col.IsDateTime)
                {
                    tdHeaderCell.Align = "center";
                }

                btn.Click += new EventHandler(Sort_Click);
            }
            else
            {
                tdHeaderCell.InnerHtml = String.IsNullOrEmpty(overrideText) ? overrideText : col.DisplayName;
            }
        }

        #region Table Builders

        private void BuildHeader()
        {
            tr = new HtmlTableRow();

            string[] customCols = columnList.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries);
            if(customCols.Length != 0)
            {
                foreach(string s in customCols)
                {
                    td = new HtmlTableCell();
                    if(!String.IsNullOrEmpty(tableHeaderCSSClass))
                    {
                        td.Attributes.Add("class", tableHeaderCSSClass);
                    }
                    else
                    {
                        td.Attributes.Add("style", tableHeaderStyle);
                    }

                    if(s.Contains(":"))
                    {
                        //it's a cast in the form of "productID:ID"
                        string[] castedList = s.Split(new char[] {':'}, StringSplitOptions.RemoveEmptyEntries);

                        try
                        {
                            TableSchema.TableColumn col = schema.GetColumn(castedList[0].Trim());
                            if(col == null)
                            {
                                col = schema.GetColumn(castedList[1].Trim());
                            }
                            if(col == null)
                            {
                                throw new Exception("Can't find a column for this table named " + castedList[0] + " or " + castedList[1]);
                            }
                            else
                            {
                                colList.Add(col.ColumnName.ToLower());
                                AddHeaderText(col, td, castedList[1]);
                            }
                        }
                        catch
                        {
                            throw new Exception("Invalid Custom Columns. If you want to pass in a custom colum, it should be in the form 'columnName:Replacement Name'");
                        }
                    }
                    else
                    {
                        TableSchema.TableColumn col = schema.GetColumn(s.Trim());
                        if(col == null)
                        {
                            throw new Exception("Can't find a column for this table named " + s);
                        }
                        else
                        {
                            colList.Add(col.ColumnName.ToLower());
                            AddHeaderText(col, td, "");
                        }
                    }
                    tr.Cells.Add(td);
                }
            }
            else
            {
                //loop the schema
                foreach(TableSchema.TableColumn col in schema.Columns)
                {
                    td = new HtmlTableCell();
                    td.Attributes.Add("style", tableHeaderStyle);

                    AddHeaderText(col, td, "");

                    tr.Cells.Add(td);
                    colList.Add(col.ColumnName.ToLower());
                }
            }
            tbl.Rows.Add(tr);
        }

        private void BuildRows()
        {
            //pull the data
            //bool isEven = false;
            for (int i = tbl.Rows.Count - 1; i > 0; i--)
            {
                tbl.Rows.RemoveAt(i);
            }
            //tbl.Rows.Clear();
            string cellAttribute = String.IsNullOrEmpty(tableCellCSSClass) ? "style" : "class";
            string cellAttributeValue = String.IsNullOrEmpty(tableCellCSSClass) ? tableCellStyle : tableCellCSSClass;
            string cellAttributeAltValue = String.IsNullOrEmpty(tableCellCSSClass) ? tableAlternatingStyle : tableAlternatingCSSClass;
            int rowCount = dataSource.Rows.Count;

            for (int r = 0; r < rowCount; r++)
            {
                DataRow dr = dataSource.Rows[r];
                tr = new HtmlTableRow();
                if (Sugar.Numbers.IsEven(r))
                    tr.Attributes.Add(cellAttribute, cellAttributeValue);
                else
                    tr.Attributes.Add(cellAttribute, cellAttributeAltValue);

                int colCounter = 0;
                for (int i = 0; i < colList.Count; i++)
                {
                    string colName = colList[i].ToString();
                    TableSchema.TableColumn schemaColumn = schema.GetColumn(colName);

                    td = new HtmlTableCell();
                    if (schemaColumn.IsDateTime)
                    {
                        DateTime dt;
                        if (DateTime.TryParse(dr[colName].ToString(), out dt))
                            td.InnerHtml = dt.ToShortDateString();
                        else
                            td.InnerHtml = dr[colName].ToString();

                        td.Align = "center";
                    }
                    else if (schemaColumn.DataType == DbType.Currency)
                    {
                        decimal dCurr;
                        decimal.TryParse(dr[colName].ToString(), out dCurr);
                        td.InnerHtml = dCurr.ToString("c");
                        td.Align = "right";
                    }
                    else if (schemaColumn.IsNumeric)
                    {
                        td.InnerHtml = dr[colName].ToString();
                        td.Align = "right";
                    }
                    else
                    {
                        td.InnerHtml = dr[colName].ToString();
                    }


                    //check the linkTo
                    if (!String.IsNullOrEmpty(linkOnColumn))
                    {
                        if (Utilities.Utility.IsMatch(linkOnColumn, colName))
                        {
                            if (!String.IsNullOrEmpty(linkToPage))
                            {
                                //link on the first column by wrapping it with an HREF
                                td.InnerHtml = "<a href=\"" + linkToPage + "?id=" + dr[schema.PrimaryKey.ColumnName] + "\">" + td.InnerHtml + "</a>";
                            }
                        }
                    }
                    else
                    {
                        if (colCounter == 0)
                        {
                            if (!String.IsNullOrEmpty(linkToPage))
                            {
                                //link on the first column by wrapping it with an HREF
                                td.InnerHtml = "<a href=\"" + linkToPage + "?id=" + dr[schema.PrimaryKey.ColumnName] + "\">" + td.InnerHtml + "</a>";
                            }
                        }
                    }

                    tr.Cells.Add(td);
                    colCounter++;
                }
                tbl.Rows.Add(tr);
            }
        }

        private void BuildPager()
        {
            if(pageSize > 0)
            {
                HtmlTableRow trPage = new HtmlTableRow();
                tblPage.Rows.Add(trPage);

                HtmlTableCell tdPage = new HtmlTableCell();
                trPage.Cells.Add(tdPage);

                litPagerLabel.Text = " Page ";

                //add the pager buttons
                tdPage.Controls.Add(btnFirst);
                tdPage.Controls.Add(btnPrev);
                tdPage.Controls.Add(litPagerLabel);
                tdPage.Controls.Add(ddlPages);
                tdPage.Controls.Add(lblRecordCount);
                tdPage.Controls.Add(btnNext);
                tdPage.Controls.Add(btnLast);

                //set the text
                btnFirst.Text = buttonFirstText;
                btnLast.Text = buttonLastText;
                btnPrev.Text = buttonPreviousText;
                btnNext.Text = buttonNextText;

                //always the same
                btnFirst.CommandArgument = "1";

                //handle the page event
                btnFirst.Click += new EventHandler(Paging_Click);
                btnLast.Click += new EventHandler(Paging_Click);
                btnPrev.Click += new EventHandler(Paging_Click);
                btnNext.Click += new EventHandler(Paging_Click);


                ddlPages.SelectedIndexChanged += new EventHandler(ddlPages_SelectedIndexChanged);
                ddlPages.AutoPostBack = true;

                tdPage.ColSpan = colList.Count;
                tdPage.Align = "center";
                if(!String.IsNullOrEmpty(pagerCSS))
                {
                    tdPage.Attributes.Add("class", pagerCSS);
                }
                else
                {
                    tdPage.Attributes.Add("style", pagerStyle);
                }

                //add to the pager table
                tblPage.Rows.Add(trPage);
            }
        }

        #endregion

        #region Paging

        private void ddlPages_SelectedIndexChanged(object sender, EventArgs e)
        {
            pageIndex = int.Parse(ddlPages.SelectedValue);
            //put it to the ViewState so we know what
            //page we're on if sorting is clicked
            ViewState["currentPage"] = pageIndex;

            LoadGrid();
        }

        private void Paging_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            int pIndex = 1;
            int.TryParse(btn.CommandArgument, out pIndex);
            PageIndex = pIndex;

            //put it to the ViewState so we know what
            //page we're on if sorting is clicked
            ViewState["currentPage"] = pIndex;

            LoadGrid();
        }

        private void SetPagingButtonState()
        {
            if(ViewState["currentPage"] != null)
            {
                pageIndex = (int)ViewState["currentPage"];
            }
            else
            {
                pageIndex = 1;
                ViewState["currentPage"] = 1;
            }

            if(totalPages > 0 && totalRecords > 0)
            {
                //this is always the same
                if(pageIndex == 0)
                {
                    pageIndex = 1;
                }

                int nextPage = pageIndex + 1;
                int prevPage = pageIndex - 1;

                //command args
                btnNext.CommandArgument = nextPage.ToString();
                btnPrev.CommandArgument = prevPage.ToString();
                btnLast.CommandArgument = totalPages.ToString();


                //use
                btnPrev.Enabled = true;
                btnNext.Enabled = true;
                btnLast.Enabled = true;
                btnFirst.Enabled = true;

                if(pageIndex == totalPages)
                {
                    btnNext.Enabled = false;
                    btnLast.Enabled = false;
                }
                else if(pageIndex == 1)
                {
                    btnPrev.Enabled = false;
                    btnFirst.Enabled = false;
                }
            }
        }

        #endregion

        private void EnsureTotals(Query qry)
        {
            //if there's paging, we have to run an initial query to figure out 
            //how many records we have
            //we should only do this once...
            if(pageSize > 0)
            {
                if(ViewState[TOTAL_RECORDS] == null)
                {
                    //set it
                    TotalRecords = qry.GetRecordCount();
                    ViewState[TOTAL_RECORDS] = TotalRecords;
                }
                else
                {
                    TotalRecords = (int)ViewState[TOTAL_RECORDS];
                }
                //the pages are the records/pageSize+1
                totalPages = totalRecords / pageSize + 1;
                lblRecordCount.Text = " of " + totalPages + " (" + totalRecords + " total) ";

                if(ddlPages.Items.Count == 0)
                {
                    //set up the dropDown
                    for(int i = 1; i <= totalPages; i++)
                    {
                        ddlPages.Items.Add(new ListItem(i.ToString(), i.ToString()));
                    }
                }
            }
        }

        private void LoadGrid()
        {
            DecideSortDirection();

            //load the data
            if(!String.IsNullOrEmpty(tableName))
            {
                Query q = new Query(tableName, ProviderName);

                //set the select list
                StringBuilder selectList = new StringBuilder("*");
                if(!String.IsNullOrEmpty(columnList))
                {
                    selectList = new StringBuilder();
                    for(int i = 0; i < colList.Count; i++)
                    {
                        selectList.Append(colList[i]);
                        if(i + 1 < colList.Count)
                        {
                            selectList.Append(", ");
                        }
                    }
                }
                q.SelectList = selectList.ToString();

                //sorting
                if(!String.IsNullOrEmpty(sortBy))
                {
                    if(String.IsNullOrEmpty(sortDirection) || sortDirection.Trim() == "ASC")
                    {
                        q.OrderBy = OrderBy.Asc(sortBy);
                    }
                    else
                    {
                        q.OrderBy = OrderBy.Desc(sortBy);
                    }
                }

                //paging
                if(pageSize > 0)
                {
                    q.PageSize = pageSize;

                    //check the ViewState
                    q.PageIndex = pageIndex;

                    //set this for readability
                    ddlPages.SelectedValue = pageIndex.ToString();
                }


                //honor logical deletes
                q.CheckLogicalDelete();

                //where
                if(!String.IsNullOrEmpty(whereExpression))
                {
                    q.WHERE(whereExpression);
                }

                if(whereCollection != null)
                {
                    q.wheres = whereCollection;
                }

                DataSet ds = q.ExecuteDataSet();
                if(ds.Tables.Count > 0)
                {
                    dataSource = ds.Tables[0];
                }
                else
                {
                    throw new Exception("Bad query - no data returned. Did you set the correct provider?");
                }

                EnsureTotals(q);
                //set the buttons
                SetPagingButtonState();
                //create a table
                BuildRows();

            }
            else
            {
                throw new Exception("No tableName property set - please be sure to set the name of the table or view you'd like to see");
            }


        }

        #region sorting

        private void Sort_Click(object sender, EventArgs e)
        {
            //the sort event. use a view to sort the table data
            LinkButton btn = (LinkButton)sender;
            SortBy = btn.CommandArgument;
            LoadGrid();
        }

        private void DecideSortDirection()
        {
            //string sortDir = "ASC";
            if(ViewState[SORT_BY] != null)
            {
                string selectedSort = ViewState[SORT_BY].ToString();

                if(String.IsNullOrEmpty(SortBy))
                {
                    //sort wasn't clicked - a postback
                    //has reset the property to null
                    //so set the sort to what's in the viewState
                    SortBy = selectedSort;
                }
                else
                {
                    if(selectedSort == SortBy)
                    {
                        //the direction should be desc
                        SortDirection = " DESC";

                        //reset the sorter to null
                        ViewState[SORT_BY] = null;
                    }
                    else
                    {
                        //this is the first sort for this row
                        //put it to the ViewState
                        ViewState[SORT_BY] = SortBy;
                    }
                }
            }
            else
            {
                //if this is the first sort, store it in the ViewState
                ViewState[SORT_BY] = SortBy;
            }
        }

        #endregion

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            tbl.CellPadding = 3;
            tbl.CellSpacing = 0;
            tbl.Width = "100%";
            tblPage.Width = "100%";

            //add three rows to this table
            //i know this might seem sort of strange
            //but given that we're dealing with eventing of buttons
            //.NET is a bit clumsy about it - these controls
            //need to exist in the control bag in order for the 
            //event to be recognize. So we add them up front

            trTop.Cells.Add(tdTop);
            tblWrap.Rows.Add(trTop);
            trBottom.Cells.Add(tdBottom);
            tblWrap.Rows.Add(trBottom);

            tdTop.Controls.Add(tbl);
            tdBottom.Controls.Add(tblPage);
            Controls.Add(tblWrap);

            //set CSS
            if(!String.IsNullOrEmpty(tableCSSClass))
            {
                tbl.Attributes.Add("class", tableCSSClass);
            }
            else
            {
                tbl.Attributes.Add("style", tableStyle);
            }

            if(!String.IsNullOrEmpty(pagerButtonCSS))
            {
                btnFirst.Attributes.Add("class", pagerButtonCSS);
                btnPrev.Attributes.Add("class", pagerButtonCSS);
                btnNext.Attributes.Add("class", pagerButtonCSS);
                btnLast.Attributes.Add("class", pagerButtonCSS);
                ddlPages.Attributes.Add("class", pagerButtonCSS);
            }
            else
            {
                btnFirst.Attributes.Add("style", pagerButtonStyle);
                btnPrev.Attributes.Add("style", pagerButtonStyle);
                btnNext.Attributes.Add("style", pagerButtonStyle);
                btnLast.Attributes.Add("style", pagerButtonStyle);
                ddlPages.Attributes.Add("style", pagerButtonStyle);
            }

            //have to load up the pager buttons to the control set so we recognize them on 
            //postback

            //load the schema
            schema = DataService.GetSchema(tableName, ProviderName, TableType.Table);
            if(schema == null)
            {
                throw new Exception("Can't find a table names " + tableName + "; did you set the correct providerName?");
            }

            //load the headers
            BuildHeader();

            BuildPager();

            //if(!Page.IsPostBack)
            //{
                LoadGrid();
                
                trBottom.Visible = !(pageSize >= totalRecords);
            //}
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Alex Mueller
Web Developer
United States United States
No Biography provided

You may also be interested in...

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170813.1 | Last Updated 17 Nov 2007
Article Copyright 2007 by Alex Mueller
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid