More

    搜索頁面 – ViewModel的定義 (.NET MVC 5 Ch-21)

    在上一篇介紹完了搜索功能的概念和思路之後,在這一篇開始要看實作的部份。

    通常寫Mvc都是從Model開始,因此這一篇將來看一下搜索功能所會使用到的ViewModel

    同步發表於我的部落格:http://alantsai2007.blogspot.com/2014/10/BuildYourOwnApplicationFrameworkOnMvc-21-IndexPage-ViewModel.html

    ViewModel的內容

    首先,搜索的ViewModel必然會有兩個Property:

    1. 搜索條件
    2. 搜索結果

    因此,我們會先從這兩個部份的Property來看起。

    搜索條件的ViewModel

    搜索條件會有一定有的欄位和各個domain所需要的欄位,因此會先定義一個Base,好方便之後domain來繼承並且提供其他相關欄位。

    一定會有的欄位像是:

    1. 每頁筆數
    2. 目前頁數
    3. 排序欄位
    4. 排序順序

    Domain相關的欄位就依照各自的需求,例如假設是一篇文章,可能會有以「標題」做搜索或者以「內文」做搜索。

    因此,程式碼會如下:

    /// <summary>
    /// 搜索 Form 的 ViewModel base。定義搜索必須要有的相關欄位。
    /// </summary>
    public abstract class SearchFormViewModelBase : ISearchFormViewModelBase
    {
        /// <summary>
        /// 目前頁數的值
        /// </summary>
        private int page;
    
        /// <summary>
        ///  取得或設定目前頁數。最小值是1。
        /// </summary>
        /// <value>
        /// 目前頁數
        /// </value>
        public virtual int Page
        {
            get
            {
                if (this.page < 1)
                {
                    this.page = 1;
                }
    
                return this.page;
            }
    
            set { this.page = value; }
        }
    
        /// <summary>
        /// 每頁筆數的值
        /// </summary>
        private int pageSize;
    
        /// <summary>
        /// 取得或設定每頁筆數。最小值是15。
        /// </summary>
        /// <value>
        /// 每頁筆數
        /// </value>
        public virtual int PageSize
        {
            get
            {
                if (this.pageSize < 1)
                {
                    this.pageSize = 15;
                }
    
                return this.pageSize;
            }
    
            set { this.pageSize = value; }
        }
    
        /// <summary>
        /// 欄位排序的值
        /// </summary>
        protected string orderByColumnName;
    
        /// <summary>
        /// 取得或設定要依照那個欄位做排序。
        /// </summary>
        /// <value>
        /// 依照那個欄位做排序.
        /// </value>
        public abstract string OrderByColumnName { get; set; }
    
        /// <summary>
        /// 取得或設定排序的方向。
        /// </summary>
        /// <value>
        /// <c>true</c> 表示用 ascending排序; otherwise, <c>false</c>.
        /// </value>
        public bool IsAscending { get; set; }
    }
    

    這個ViewModel實作的Interface就不看了,基本上就是這些Property的定義。

    這邊有個地方可以注意到就是排序的欄位。因為我們這個SearchFormViewModelBase沒有形態的概念,而通常來說搜索條件會和某一個DB的Table對應。因此,為了方便之後框架幫忙做搜索,這邊又定義一個有強型別的SearchFormViewModelBase:

    /// <summary>
    /// 搜索 Form 的 ViewModel base。有帶上形態,以第一個欄位做排序
    /// </summary>
    /// <typeparam name="T">Entity Framework裡面Table Entity</typeparam>
    public abstract class SearchFormViewModelBase<T> : SearchFormViewModelBase
    {
        /// <summary>
        /// 取得或設定要依照那個欄位做排序。
        /// </summary>
        /// <value>
        /// 依照那個欄位做排序.
        /// </value>
        public override string OrderByColumnName
        {
            get
            {
                if (string.IsNullOrEmpty(this.orderByColumnName))
                {
                    this.orderByColumnName = typeof(T).GetProperties().First().Name;
                }
    
                return this.orderByColumnName;
            }
    
            set
            {
                this.orderByColumnName = value;
            }
        }
    }
    

    可以注意到這個Class的定義是Abstract,表示之後的class應該要依照自己的Domain去做繼承,例如如果今天是Post的搜索ViewModel,希望有一個 「標題」的搜索欄位,和排序要以「建立時間」欄位,那麼ViewModel就會是:

    public class SearchFormViewModel : SearchFormViewModelBase<Post>
    {
        [DisplayName("標題")]
        public string Title { get; set; }
    
        public override string OrderByColumnName
        {
            get
            {
                return "CreateDateTime";
            }
        }
    }
    

    搜索結果

    這個部份就比較簡單,就是某一個和Detail頁面一樣ViewModel不過是被一個IPagedList包住。因此他不會像搜索ViewModel一樣有個base而是直接看定義的 ViewModel然後以泛型的方式傳入。

    PagedList.Mvc – 好用的分頁套件

    搜索ViewModel的主檔

    有了這兩個Property的ViewModel之後,就可以建立搜索的ViewModel的Base:

    /// <summary>
    /// 搜索頁面的ViewModel需要繼承這一個Base。
    /// 方便處理Paging和搜索條件相關。
    /// 這個方法就兩個Property,用作於表示搜索的form和搜索結果的result。
    /// </summary>
    /// <typeparam name="TSearchForm">搜索的form ViewModel type。
    /// 必須是繼承<see cref="MvcInfrastructure.Common.Base.SearchFormViewModelBase"/>
    /// </typeparam>
    /// <typeparam name="TPageResult">搜索的結果ViewModel type</typeparam>
    public class SearchViewModelBase<TSearchForm, TPageResult> : 
    	ISearchViewModelBase<TSearchForm, TPageResult>
        where TSearchForm : Core.Common.Base.ISearchFormViewModelBase, new() 
    {
        private TSearchForm searchForm;
    
        /// <summary>
        /// 取得或設定搜索的Form。如果是null,會實例一個。
        /// </summary>
        /// <value>
        /// 搜索的Form
        /// </value>
        public TSearchForm SearchForm
        {
            get
            {
                if (this.searchForm == null)
                {
                    this.searchForm = new TSearchForm();
                }
    
                return this.searchForm;
            }
    
            set { this.searchForm = value; }
        }
    
        /// <summary>
        /// 取得或設定搜索結果的ViewModel。
        /// </summary>
        /// <value>
        /// 搜索結果的ViewModel。用<see cref="PagedList.IPagedList"/>包住,方便做分頁
        /// </value>
        public IPagedList<TPageResult> Result { get; set; }
    }
    

    Post的搜索ViewModel

    定義好了搜索的BaseViewModel之後,假設今天是Post頁面要做搜索的ViewModel,就可能會像是:

    public class Index : SearchViewModelBase<SearchFormViewModel, SearchResult>
    {
    }
    
    public class SearchResult : IMapFrom<Post>
    {
        public int Id { get; set; }
        [DisplayName("標題")]
        public string Title { get; set; }
        [DisplayName("內文")]
        public string PostContent { get; set; }
    
    }
    
    public class SearchFormViewModel : SearchFormViewModelBase<Post>
    {
        [DisplayName("標題")]
        public string Title { get; set; }
    
        public override string OrderByColumnName
        {
            get
            {
                return "CreateDateTime";
            }
        }
    }
    

    結語

    有了搜索的ViewModel之後,在下一篇將會介紹框架的Service怎麼能夠做修改並且讓搜索處理邏輯變的簡單。

    Source : https://ithelp.ithome.com.tw/articles/10159677

    Recent Articles

    spot_img

    Related Stories

    Stay on op - Ge the daily news in your inbox