顯示具有 ASP .NET MVC 標籤的文章。 顯示所有文章
顯示具有 ASP .NET MVC 標籤的文章。 顯示所有文章

Swagger: Unable to render this defition

最近用.NET Core開發API專案,本來順順好用的Swagger突然無法提供服務








後來發現是Function Naming造成,例如本來有個方法叫做GetOrders,後來又新增另一個方法叫做GetOrdersAsync,就會讓Swagger用來呈現API定義的頁面失效,要解決此問題不是去調整Swagger,而是調整Function Naming~~不要使用Async結尾的命名方式!!!

原因如下(微軟官方說明)

        從ASP .NET Core 3.0開始,ASP .NET Core MVC會自動把字尾(suffix)的Async移除,routing和link都會受到此預設影響。

解決方法

        方法1:修改性services.AddMvc(options => options.SuppressAsyncSuffixInActionNames = false);

        方法2:Rename Function避免使用Async字尾

Telerik Grid Custom Binding by TelerikMvcGridCustomBindingHelper


Telerik Grid可設置.Sortable()、.Pageable()、.Groupable()、.Filterable()達到排序、分頁、分群、過濾資料的效果,但這是使用Telerik所提供的binding為前提。

若採用CustomBinding,以上效果(排序、分頁、分群、過濾)全部都要自行實作,實作方式請參考官網CustomBinding,或是直接下載官方論壇提供的範例


依官方解法,每次CustomBinding都要針對Binding的資料結構各實作paging、sorting、grouping一次,尤其grouping更要事先設計好針對那些欄位是可以排序的。
若覺得官方解法太麻煩~~是真的很麻煩ε(┬┬_┬┬)3 ,或是資料結構過於複雜無法呈現,或你跟我一樣懶惰XDD
建議可搭配另一套件TelerikMvcGridCustomBindingHelper,達到更彈性、修改更少的寫法!

承接前篇文章Telerik Grid Custom Binding,BL與View都不用做任何改變,針對Controller所需異動描述如下

1. 至CodePlex下載TelerikMvcGridCustomBindingHelper套件
解壓或用NuGet安裝裡面二支library
download:http://tgh.codeplex.com/
library:TelerikMvcGridCustomBindingHelper.dll、TelerikMvcGridCustomBindingHelper.NHibernate.dll
version:1.10.15.247
notice:Telerik要記得更新到2012 Q2

2. 加入AutoMapper參考
download link:使用NuGet下指令安裝,指令為PM> Install-Package AutoMapper 
version:2.1.267.0

3. 把Helper要用到的另二種library下載回來參考
download:http://nhforge.org/Default.aspx
library:NHibernate.dll、Iesi.Collections.dll
version:3.3.1.4000

4. 修改Controller寫法
[GridAction(EnableCustomBinding = true)]
public ActionResult ListPO_CustomBinding(GridCommand command)
{
int totalCount = POService.QueryPOListIndex(command);
ViewBag.POTotalCount = totalCount;
List<PO> data = POService.QueryPOList(command);

//使用TelerikMvcGridCustomBindingHelper
for (int i = 0; i < (command.Page - 1) * command.PageSize; i++)
{
PO dd = new PO();
data.Insert(0, dd);
}
IQueryable<PO>
query = data.AsQueryable();
var gridHelper = new GridCustomBindingHelper<PO, PO>(command, query);
var gridModel = gridHelper.BuildGridModel();
gridModel.Total = ViewBag.POTotalCount;
return View(gridModel);

}


仔細比較與前篇寫法的差異處(黃色highlight),只要修改Controller一點點就省去實作N遍的paging、sorting、grouping
真是太感謝TelerikMvcGridCustomBindingHelper的開發團隊╭ (′▽`)╭(′▽`)╭(′▽`)╯

Telerik Grid Custom Binding

Telerik Grid算是做得很完善,API也多~但客製化需求還是在所難免。
比如有個表單系統只提供最簡單的資料瀏覽,姑且不論是否下查詢條件,要是資料百萬筆豈不是起肖?!

較好的做法是用分頁區別之餘,但每次只取該分頁的資料,而不是一次取回百萬筆資料再作分頁

本文就要來介紹,如何實作Custom Binding

1. 計算總筆數(因為是CustomBinding,GridModel需要的總筆數必須自己計算)
public int QueryPOListIndex(GridCommand command)
{
var entity = mydata.PO.AsQueryable();
int ttlCount = entity.ToList().Count();
return ttlCount;
}


2. 像平常一樣取資料(請依照自己的需求和資料作變化)
public List<PO> QueryPOList(GridCommand command)
{
var entity = mydata.PO.AsQueryable();
//Sorting(必須有Default的Order By條件,否則會Error)
entity = entity.OrderBy(order => order.PONo);
//Then paging
if (command.PageSize > 0)
entity = entity.Skip((command.Page - 1) * command.PageSize);
entity = entity.Take(command.PageSize);
return entity.ToList();
}


前面二項為Bussiness Layer(POService),若專案架構較小~亦可將其寫在Controller中
3. Controller
//須注意的是, ViewBag.DataTotalCount在此頁載入時須先給予一預設值(ex:0),之後的查詢function再賦予正確值
public ActionResult ListPO()
{
ViewBag.POTotalCount = 0;
return View();
}

[GridAction(EnableCustomBinding = true)]
public ActionResult ListPO_CustomBinding(GridCommand command)
{
int totalCount = POService.QueryPOListIndex(command);
ViewBag.POTotalCount = totalCount;
List<POt> data = POService.QueryPOList(command);
return View(new GridModel
{
Data = data,
Total = totalCount
});
}


4. View
@(Html.Telerik().Grid<PO>()
.Name("Grid")
.Columns(columns => {
columns.Bound(c => c.PONo);
columns.Bound(c => c.DocDate);
columns.Bound(c => c.Company);
columns.Bound(c => c.Vendor);
columns.Bound(c => c.Status);
columns.Bound(c => c.CmpltReceived);
})
.Pageable(settings => settings.Total((int)ViewBag.POTotalCount))
.DataBinding(dataBinding => dataBinding.Ajax().Select("ListPO_CustomBinding", "Inbound"))
.EnableCustomBinding(true)

.Sortable()
.Groupable()
)

Disable Automatic DataBinding


無論Telerik或Kendo UI的Grid,在頁面render時必定會去讀取要綁在Grid上的資料,也就是執行MVC中的Action method並將資料呈現在UI上,
以Telerik為例(@Html.Telerik().Grid< mydocument>()
.Name("Grid")
.DataBinding(d => d.Ajax().Select("Query", "Home"))
)

以Kendo UI為例@(Html.Kendo().Grid< myDocument>()
.Name("Grid")
.DataSource(dataSource => dataSource.Ajax()
.ServerOperation(false)
.Read(read => read.Action("Query", "Home")))
)


但,如果你期望一開始不做任何DataBinding,只放個白白的Grid,等使用者確實下條件才去後端撈資料,那就要想辦法阻止automatic databinding這件事發生,
Telerik的做法,是利用OnDataBinding的event// 判斷是否第一次載入
var isFirstLoad = true;
function onDataBinding(e) {
// 當第一次載入,不呼叫 Grid Ajax Select,直接 return
if (isFirstLoad) {
e.preventDefault();
return;
}
}

定義Grid Event
.ClientEvents(c => c.OnDataBinding("onDataBinding"))

那Kendo UI呢?
根據官方說法,目前尚未提供可取消DataSource之RequestStart的event
Currently it is not possible to cancel the RequestStart event of the DataSource. 
We will provide such functionality in the future releases. I am sorry for the inconvenience.

既然前端沒有event可阻擋,那只好在後端撈資料時丟個空instance給Grid,一樣能binding不拋錯,希望未來能盡快release這個event,不然還要多跑一次Action method

Getting Started with Kendo UI

首先來個Kendo UI的網址http://docs.kendoui.com/
雖然正式版剛釋出,但網路上能找的資源差不多都在這了

Kendo UI Complete for ASP.NET MVC(以下簡稱Kendo UI)使用方式和Telerik Extensions for ASP.NET MVC(以下簡稱Telerik)一樣,可下載壓縮檔自行解壓取用檔案,也可使用安裝檔直接將檔案裝在特定路徑。
這邊以安裝檔的方式快速截圖,並說明使用方式如下:




安裝完畢請瀏覽至C:\Program Files (x86)\Telerik\Kendo UI for ASP.NET MVC Q2 2012
  • 將js資料夾所有檔案複製到MVC專案的Scripts
  • 將styles資料夾所有檔案複製到MVC專案的Content
  • 加入Binary參考,路徑為wrappers\aspnetmvc\Binaries\Mvc3\Kendo.Mvc.dll
  • 在主版頁面加入下列資訊<link rel="stylesheet" href="@Url.Content("~/Content/kendo.common.min.css")">
    <link rel="stylesheet" href="@Url.Content("~/Content/kendo.default.min.css")">
    <script src="@Url.Content("~/Scripts/kendo.web.min.js")"></script>
    <script src="@Url.Content("~/Scripts/kendo.aspnetmvc.min.js")"></script>
  • web.config與Views\web.config皆加上namespace<add namespace="Kendo.Mvc.UI" />

Done!

Kendo UI誕生

Telerik前陣子放出消息,表示支援Telerik Extensions for ASP.NET MVC只到明年(2013 Q3),
而最大更新差不多就停留在目前的2012 Q2,之後版本多是修正bug和提升performance

取而代之的是這套Kendo UI Complete for ASP.NET MVC,今年7月已推出正式版,
簡單來說就是Kendo UI=CSS 3 + Html 5 + Javascript,以現階段版本還比不上Telerik的完善,開發文件也不盡完全,還不用急著升級
但未來若要朝MVC 4升級,可能要考慮轉用這套(Telerik Extensions for ASP.NET MVC只支援到MVC 3),另外Kendo對REST也提供比較好的支援,以微軟將推出的.Net Framework 4.5來看也是有此趨勢。

其他參考資訊
官方對一些疑慮的釐清
從Telerik升級到Kendo
Kendo UI Complete for ASP.NET MVC

使用jQuery傳遞Array

之前寫過一篇善用JavaScriptSerializer處理JSON資料,這次要傳遞的資料比較簡單,不是string就是List< string>,想當然爾會直覺地在前端用Array處理~方便咩。

JavaScript的Array長這樣
var myList = new Array();
最常見的用法就是把網頁上表單形式的排列資料,依所需取出以組合成陣列,
像是把table裡面每個的id值取出來
$('#myTable  tr').each(function () {
     var myId = $(this).attr('id');
     myList.push( myId  );
})
接著用$.post把資料往後送(我用MVC所以會有個Action接收)
$.post('myController/myAction', { json1: $.trim($('#textbox1').val()), json2: myList }, null, "json");

myAction如下
[HttpPost]
public JsonResult  myAction (string  json1, List< string>   json2)
{
     // do something
}
經過反覆檢驗,myList的確有值但json2總是null
解決辦法是traditional設為true,寫法有以下二種

● $.ajax設定traditional: true
$.ajax({
    type: "POST",
    url: 'myController/myAction',
    data: { json1: $.trim($('#textbox1').val()), json2: myList },
    null,
    dataType: "json",
    traditional: true
    // traditional 改為 ture .NET 才能成功接收陣列
});

● $.post傳值必須使用jQuery.param
var myObject = { json1: $.trim($('#textbox1').val()), json2: myList };
$.post('myController/myAction', $.param(myObject, true), null, "json");

參考資料
jQuery.param()
How can I post an array of string to ASP.NET MVC Controller without a form?

New <%: %> Syntax for HTML Encoding

依據 ScottGu先生文章,釐清新語法之觀念

●HTML Encoding
●New <%: %> Code Nugget Syntax
為了方便開發者快速檢視自己的專案並修改,新的語法採<%:  %>,它的樣子非常類似<%= %>,同樣能render output,只是新語法會自動encode

舊版寫法要多一道Encode的手續




新版寫法會自動處理~寫來就比較簡潔





●Avoiding Double Encoding
為了避免重複Encoding,可以一律採用新語法,它會自動判斷是否需要Encode
例如Html.TextBoxFor的傳回值類型是System.Web.Mvc.MvcHtmlString,無須再Encoding

System.Web.Mvc.MvcHtmlString
來源參考:MvcHtmlString
說明:表示不應該再次編碼的 HTML 編碼字串。


●Scaffolding ASP.NET MVC 2 Views
透過VS2010的Scaffold Template為例子,展現出現在的View Template都用新語法


●Summary
新語法的好處有
1. 簡化程式,可輕易檢查/驗證網站中的HTML都有正確的encoding
2. 協助應用程式免於XSS(cross-site script injection) 和 HTML injection攻擊


參考文章
1. New <%: %> Syntax for HTML Encoding Output in ASP.NET 4 (and ASP.NET MVC 2)
2. Html Encoding Code Blocks With ASP.NET 4

reload DropdownList values in asp.net mvc3 without refreshing page

以MVC撰寫的網頁上有個DropdownList,頁面初次載入是透過ViewBag來賦予值,在觸發某事件後需重新載入新值。
但DropdownList會因頁面沒有refresh,無法抓取ViewBag的新值。
解決方式可透過getJSON,寫法如下

UI
@Html.DropDownList("NameList", @ViewBag.NameList as IEnumerable)

JavaScript
function loadNames(conditionMd) {
$.getJSON("_NameList", { json: conditionMd }, function (data) {
var selectList = $("#NameList");
selectList.empty();
$.each(data, function (index, optionData) {
var option = $( '').text(optionData.Text).val(optionData.Value);
selectList.append(option);
});
});
}


C#
public ActionResult _NameList(string json)
{
Dictionary< string, string> conditions = new Dictionary< string, string>();
JavaScriptSerializer jss = new JavaScriptSerializer();
conditions = jss.Deserialize< Dictionary< string, string> >(json);
Array result = getNameValues(conditions);

List< SelectListItem> items = new List< SelectListItem>();
items.Add(new SelectListItem { Text = "Plesse select", Value = "Plesse select" });
for (int j = 0; j < result.Length; j++)
{
string[] temp1 = (string[])result.GetValue(j);
items.Add(new SelectListItem { Text = temp1[0], Value = temp1[1] });
}
return Json(items, JsonRequestBehavior.AllowGet);
}


參考資訊How to reload dropdown list values in asp.net mvc3 without refreshing page

Telerik Grid ─ Pass additional values from clientside events


Telerik GridDelete只要有unique value作為識別,就可以取得特定資料,進行刪除的動作。
unique可藉設定DataKeys達到,例如
    .DataKeys(datakeys =>
    {
        datakeys.Add(o => o.Id).RouteKey("KeyId");
        datakeys.Add(o => o.Name).RouteKey("KeyName");
    })

但有時會希望刪除後要做些額外處理,總不能設NRouteKey吧(也不是不對,蠻爛的就是….

依據Telerik論壇的資訊,可以傳遞額外的資訊,參考網址如下

若額外資訊不只一組,使用論壇建議的方法~直接用JSON包,傳值還是有問題,經過本人測試,只要一個一個指定就OK!程式碼如下
JavaScript function Grid_OnDelete(e) {
    e.values.A= $('#myA').val();
    e.values.B= $('#myB').val();
}

C#
[GridAction]
public ActionResult _AjaxDelete(string KeyId,string A, string B)
{   //略
}

最後附上完整的UI
@(Html.Telerik().Grid()
    .Name("Grid")
    .DataKeys(datakeys =>
    {
        datakeys.Add(o => o.Id).RouteKey("KeyId");
        datakeys.Add(o => o.GroupName).RouteKey("KeyGroupName");
    })
    .ToolBar(commands => commands.Insert().ButtonType(GridButtonType.Text).ImageHtmlAttributes(new { style = "margin-left:0" }))
    .Columns(columns =>
    {
        columns.Bound(o => o.GroupName);
        columns.Bound(o => o.Description);
        columns.Bound(o => o.CloudGroup);
        columns.Bound(o => o.SocialGroup);
        columns.Command(commands =>
        {
            commands.Edit().ButtonType(GridButtonType.Text);
            commands.Delete().ButtonType(GridButtonType.Text);
        });
    })
    .DataBinding(d => d.Ajax().Select("_AjaxBinding", "Partner")
        .Insert("_AjaxInsert", "Partner")
        .Update("_AjaxUpdate", "Partner")
        .Delete("_AjaxDelete", "Partner"))
    .ClientEvents(c => c.OnDelete("Grid_OnDelete"))
)

補充:不只Delete能傳遞額外資訊,Update亦可,只是要寫在OnSave event,範例如下
JavaScript
    function Grid_OnSave(e) {
        if (e.mode == 'edit') {
            e.values.A= $('#myA').val();
            e.values.B= $('#myB').val();
        }
    }

checkboxes in Telerik Grid


傳遞Telerik Grid中勾選(checkbox)的資料改良官網sample綁定單一欄位的不足,本文再針對傳遞多參數提供進階範例。

承前例,照理第二、三。。。N個參數這樣給就好
AddPartners(string[] checkedRecords, string 第二個參數, string 第三個參數)
結構一旦變成這樣,原始的checkedRecords就再也傳不過來,永遠都是null    >__<
後來發現有位老兄也遭遇相同窘境,結果Telerik論壇也沒人回=__=

後來,我改變傳遞string[]的作法,全部都用可愛的JSON來處理!!!作法如下

UI(與前文同,無須變更)
@(Html.Telerik().Grid()
.Name("Grid")
.Columns(columns => {
columns.Bound(o => o.CompanyId).ClientTemplate("< input type ='checkbox' name='checkedRecords' value='<#=CompanyId #>;<#=Name #>' / > ");
columns.Bound(o => o.Name);
columns.Bound(o => o.EnglishName);
columns.Bound(o => o.Phone);
})
.DataBinding(d => d.Ajax().Select("AjaxBinding", "Partner"))
.Pageable()
)
//按下btnAdd後要將勾選的資料傳遞到後端
< input type="button" name="btnAdd" id="btnAdd" value="Add Partner" class = "t-button" / >


JavaScript
$(document).ready(function () {
$('#btnAdd').click(function () {
var $checkedRecords = $('input[name="checkedRecords"]:checked');
if ($checkedRecords.length < 1) {
alert('你沒有選擇任何資料列!');
return;
}

var id1 = $('#myHiddenInput').val();
var id2 = $('#myDropdownList :selected').val();

//取得勾選的checkbox
var arrayChecked = new Array();
$('input[name="checkedRecords"]:checked').each(function () {
arrayChecked.push($(this).val());
});
//送出前轉換成JSON格式
var jsonChecked = JSON.stringify(arrayChecked);

$.post('AddPartners', { jsonChecked: jsonChecked, id1: id1, id2: id2 },
function(Data) {
alert(Data.Message);
}, 'json');
});
});


C#
public ActionResult AddPartners(string jsonChecked, string id1, string id2)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
string[] checkedRecords;
checkedRecords = jss.Deserialize(jsonChecked);
try
{
for (int i = 0; i < checkedRecords.Length; i++)
{
string[] Values = checkedRecords[i].Split(';');
string aa = Values[0];
string bb = Values[1];
//aa 和 bb就是前面組合的CompanyId和Name,接下來就可以繼續做其他運算
}
return new JsonResult { Data = new { Flag = "Y", Message = "OK!" } };
}
catch (Exception ex)
{
return new JsonResult { Data = new { Flag = "N", Message = ex.Message } };
}
}

Telerik Grid的水平捲軸

Telerik Grid資料過多時除分頁設定.Pageable(),還可使用.Scrollable()讓Grid有捲軸可拉動,一般只有垂直方向出現捲軸,那是因為Column寬度沒設定!
若水平方向也要有捲軸必須把所有Column寬度都設定好,否則Telerik會自動以最佳寬度去排列資料,造成資料行無限長~~版面破碎的情況。

設定範例如下
@(Html.Telerik().Grid< mydocument>()
.Name("Grid")
.Columns(columns => {
columns.Bound(o => o.UserName).Width(100);
columns.Bound(o => o.UserId).Width(200);
columns.Bound(o => o.Address).Width(100);
})
.DataBinding(d => d.Ajax().Select("_AjaxBinding", "Home"))
.Scrollable())

參考出處
網址:MVC Grid Horizontal Scrolling
資訊:Horizontal scrolling is enabled automatically in case the total width of the columns exceeds the width of the grid  and the Scrollable method is invoked. Make sure you have specified the width of your columns though.

Telerik Grid之OnSave event

OnSave event的撰寫大概不脫下列模式
< script type="text/javascript">
function Grid_onSave(e) {
var dataItem = e.dataItem;
var values = e.values;
var form = e.form;
//event handling code
}

又MVC中常使用強型別,傳遞整個Model作資料更新,如果你的頁面僅止於最簡單的Model傳遞,那麼OnSave enevt一般是極少用到。

但總是有些情況需要新舊值比對(驗證等等),那麼就要仔細注意e.dataItem與e.values的差別!
e.dataItem  →  舊的值(本來的資訊~存在DB的)
e.values       →  新的值(使用者keyin~準備更新的新資訊)

當然二者都是值的集合,若要取單一值,直接指定欄位名稱即可。假設有個自定義Model如下
public class UserInfo{
public string UserName { get; set; }
public string UserId { get; set; }
public string Company { get; set; }
}

如果要取UserName的新舊值
var oldUser = e.dataItem.UserName; //舊的值
var newUser = e.values.UserName; //新的值

傳遞Telerik Grid中勾選(checkbox)的資料

Telerik Grid透過client-side templates去擺放checkbox,可讓使用者勾選資料以進一步傳遞多選的資料列,範例網址grid_checkbox_ajax
該範例只綁定單一欄位(欄位類型Int),本文示範前端如何綁定多個欄位,以及後端接收後的重組方式

UI
@(Html.Telerik().Grid()
.Name("Grid")
.Columns(columns => {
columns.Bound(o => o.CompanyId).ClientTemplate("< input type ='checkbox' name='checkedRecords' value='<#=CompanyId #>;<#=Name #>' / > ");
columns.Bound(o => o.Name);
columns.Bound(o => o.EnglishName);
columns.Bound(o => o.Phone);
})
.DataBinding(d => d.Ajax().Select("AjaxBinding", "Partner"))
.Pageable()
)
//按下btnAdd後要將勾選的資料傳遞到後端
< input type="button" name="btnAdd" id="btnAdd" value="Add Partner" class = "t-button" / >


Javascript
$(document).ready(function () {
$('#btnAdd').click(function () {
var $checkedRecords = $(':checked');
//先確認使用者是否沒有勾選任何資料
if ($checkedRecords.length < 1) {
alert('你沒有選擇任何資料列 !');
return;
}
//把勾選的資料傳到後端
$.post('AddPartners', $checkedRecords,
function (Data){
alert(Data.Message);
}, 'json');
});
});


C#
[HttpPost]
public ActionResult AddPartners(string[] checkedRecords)
{
try
{
for (int i = 0; i < checkedRecords.Length; i++)
{
string[] Values = checkedRecords[i].Split(';');
string aa = Values[0] ;
string bb = Values[1] ;
//aa 和 bb就是前面組合的CompanyId和Name,接下來就可以繼續做其他運算
}
return new JsonResult { Data = new { Flag = "Y", Message = "OK !" } };
}
catch (Exception ex)
{
return new JsonResult { Data = new { Flag = "N", Message = ex.Message } };
}
}

善用JavaScriptSerializer處理JSON資料

MVC開發常透過jQuery傳值,前陣子發現System.Web.Extensions提供一款好用的System.Web.Script.Serialization.JavaScriptSerializer,前端傳來的JSON資料只要下個簡單的JavaScriptSerializer,就能輕易將資料由JSON formate還原為想要的格式呢!

前幾天看到同事傳遞ListBox所有option到後端,方法是自組html string,後端接收到再反向重組成其他格式(例如SelectListItem),前後端都要大費不少行數去轉換資料~
後來piggy改採JavaScriptSerializer,輕輕鬆鬆就達到相同效果!寫法如下:


1.前端將ListBox內所有option組成JSON formate data
data以javascript的Array組合
function OK() {
var result = new Array();
$("#myListBox1 option").each(function () {
var item = {
Value: $(this).val(),
Text: $(this).text()
};
result.push(item);
});
var json = JSON.stringify(result);
$.ajax({
url: '@Url.Action("MyAction")',
type: 'POST',
data: { json: json }
});
}


2.後端接收資料以JavaScriptSerializer處理
public void MyAction(string json)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
List< selectlistitem> myList = new List< selectlistitem>();
myList = jss.Deserialize< List< selectlistitem>>(json);
}

隱藏Telerik Grid之更新按鈕

使用Telerik Grid for MVC除非有極特殊需求,一般還是建議採官方提供的用法,不然前後端有時候都要自己多做工還蠻麻煩的XD

Grid在資料編輯方面有Insert、Update、Delete、BatchEditing
最近做的專案需要Insert & Delete(本文不討論Batch)但又不允許使用者Update,可是Update按鈕和Insert按鈕是同一個!!!  請看下列連環圖說明

預設編輯畫面(可以Insert、Update、Delete)
上方的"Add new record"按鈕可插入一筆新資料,右側的"Commands"欄位有"Edit"和"Delete"按鈕,但Edit按鈕身兼二職~請續看連環圖
圖一

click圖一的Edit按鈕後,該列資料會開啟編輯狀態(例如label變成可輸入的input),本來的Edit按鈕也因編輯狀態而變成"Update"按鈕
圖二

click圖一的Add new record按鈕後,會新增一筆空白資料列,本來的Edit按鈕因新增變成"Insert"按鈕
圖三

簡單來說,就是我不希望有圖二的狀態出現,但又想使用Telerik提供的event去完成Insert & Delete。最快(偷懶)的方式就是把圖一Edit按鈕隱藏,實作方式如下

1.在Grid加入ClientEvent
.ClientEvents(c => c.OnDataBound("Grid_OnDataBound"))

2.撰寫Grid_OnDataBound事件
function Grid_OnDataBound(e) {
$("a:contains('Edit')").hide();
}

此寫法只會將< a>中有Edit的部分隱藏,不影響Add new record要用的Insert按鈕,請安心使用 0.<

Telerik Extensions for ASP .NET MVC(Version Q1 2012)

之前寫過詳細的Telerik Extensions for ASP .NET MVC服用文,針對舊文的第二點"web.config加入下列設定"更新一下資訊。

Telerik已經將繁複的設定改為一行解決,以我目前使用的版本(Q1 2012)為例,只要在web.config加上此行即可使用,其餘都不用再多寫!!!
<add namespace="Telerik.Web.Mvc.UI" />

官方說明網頁在這http://www.telerik.com/help/aspnet-mvc/getting-started-using-telerik-extensions-for-asp.net-mvc-in-your-project.html

ASP .NET MVC多國語系( Globalization / Localization )

於ASP .NET網站實現多國語系非難事,但MVC就沒那麼好。
網路上流傳的用法多半是Matt Hawley所寫的超好用HtmlHelper,使用方法請參見保哥的文章,有非常詳細的說明。

最近開發MVC 3專案發現Matt Hawley提供的class需小幅修改,改完後使用雖無問題,但使用他人作品畢竟存在版本問題,剛好看到Alex Adamyan提供另一種方式,只要使用Visual Studio就可解決,就決定改採Alex Adamyan的作法

介紹Alex Adamyam作法前,預習如何在MVC使用Global Resource
SETP 1:
在App_GlobalResources資料夾加入新資源檔,例如myResource.resx、myResource.zh-TW.resx
在resx中添加要使用的資源變數,例如myString1
SETP 2:
專案rebuild後,即可在View中輕鬆存取資源,無須額外設定或include外部class
使用語法是 <%= Resources.myResource.String1 %>
==============================================
以下正式說明Localization作法by Alex Adamyan

SETP 1:加入resx(資源檔)至App_LocalResources
新增resx檔案及其初始屬性
resx內容


SETP 2:變更resx的Access Modifier為Public
Access Modifier預設為No code generation,修改後resx的Custom Tool屬性會自動變為PublicResXFileCodeGenerator
修改Access Modifier
自動變更的Custom Tool屬性


SETP 3:修改resx的Properties
Build Action : Embedded Resource
Custom Tool Namespace : 無特殊命名規則,只是為專案方便取用而賦予
Copy to Output Directory : Copy always或Copy if newer
修改屬性值


SETP 4:Save & Rebuild即可於view page使用Local Resource


SETP 5:在Global指定culture
頁面載入要顯示何種語系大致上有三種方式
(1).直接指定Culture
(2).讀取web.config的globalization設定
(3).以使用者瀏覽器的預設語系為主
本文示範較能滿足多數用戶的作法(3).
protected void Application_AcquireRequestState(object sender, EventArgs e) {
//取得瀏覽器第一個語系 string lang = HttpContext.Current.Request.UserLanguages[0]; CultureInfo ci = new CultureInfo(lang); System.Threading.Thread.CurrentThread.CurrentUICulture = ci; System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name); }


SETP 6:成功顯示當地語系(繁體中文)

Telerik Grid for ASP .NET MVC基本設定

前文準備好開發環境,開始使用Telerik最威的Grid componment

顧及資料龐大與server端,我們採用AJAX作為databinding的方式,而Telerik Grid若只作查詢只要撰寫databinding用的func.即可。一個樣式豐富又基本的Grid設定如下
<%= Html.Telerik().Grid < TelerikDemo.Models.Model1 >() .Name("Grid") //Column設定 .Columns(columns => { //隱藏欄位 columns.Bound(u => u.Id).Hidden(true); //欄位寬度 columns.Bound(u => u.Name).Width(120); //欄位表頭 columns.Bound(u => u.Age).Title("年齡"); //欄位格式 columns.Bound(u => u.Birth).Format("{0:yyyy/MM/dd}"); //欄位以其他控制項呈現 columns.Bound(u => u.Status) .ClientTemplate("< select > < option value='< #= Status # >' selected='selected' >< #= Status # >< /option >< /select >"); //欄位樣式(直接設定) columns.Bound(u => u.Tel). HtmlAttributes(new { style = "color: green" }); }) //資料繫結Select(actionName, controllerName) .DataBinding(dataBinding => dataBinding.Ajax().Select("_BindingModel1", "Grid")) //頁籤設定 .Pageable(paging => paging.PageTo(3)//初載時顯示第幾頁 .Position(GridPagerPosition.Both)//分頁的位置 //提供多個PageSize讓用戶彈性更改一頁呈現幾筆資料,而決定PageSize的控制項是PageSizeDropDown .PageSize(10, new int[] { 5, 10, 20 }) //PageInput讓使用者以keyin方式直接跳到想要的page ; //NextPreviousAndNumeric表示同時提供上/下一頁與數字頁的功能 ; //PageSizeDropDown提供下拉式選單更改每頁的筆數 .Style(GridPagerStyles.PageInput | GridPagerStyles.NextPreviousAndNumeric | GridPagerStyles.PageSizeDropDown)) //排序設定 .Sortable(sorting => sorting.OrderBy(order => order.Add(u => u.Name))) //表格scrollbar .Scrollable() //資料分組 .Groupable() //資料過濾 .Filterable() .Selectable() .ClientEvents(e => e.OnRowSelect("onRowSelected")) %>


至此,在GridController寫個名為_BindingModel1的func.負責取回可於Telerik Grid顯示的資料,Grid就可執行無誤。
另外,最後的onRowSelected則是撰寫於前端的js function,主要是在觸發client端的row on select時告訴Grid要執行的事情,非必要項~~依專案需求與否再加即可。

Telerik Extensions for ASP .NET MVC

MVC有點黏又不太黏的關係,讓前端開發相較傳統ASP .NET有點點不順手,尤其"查詢"一直佔系統的大宗,如何將大量複雜的資料以優美介面呈現予用戶就顯得非常重要!

網路上不少佛心來的第三方控件,本文將介紹TELERIK公司開發的Telerik Extensions for ASP.NET MVC(以下簡稱Telerik)

和其他open source一樣可使用MSI檔auto install或自解壓縮檔至對應路徑,本人懶惰就直接使用MSI搞定,但若有特殊版本需求請自行上網download解壓。

另外要特別注意Telerik支援的MVC版本,以本文2011 Q2(2011/7/12 release)為例支援MVC 1、2、3,但並非""同時支援""多重版本,不同版本請refrence相應的Telerik.Web.Mvc.dll
Telerik安裝完畢在C:\Program Files的檔案架構

VS2010多了專屬Telerik的Project Template

若專案規模不大,又懶得手動設定所需的相關檔案,可參照上圖選用Telerik MVC 3 Web Application,毋須額外設定即可著手撰寫專案 0 . <


話說回來,採用MVC開發的系統都不小,要如何在團隊規劃的架構下順順使用Telerik呢?
假設Telerik安裝完畢且MVC開發環境也備齊,使用方式如下 :

1. 於MVC的WEB專案參考Telerik.Web.Mvc.dll(注意MVC版本)

2. web.config加入下列設定
<add namespace="Telerik.Web.Mvc.UI"/> 
<sectionGroup name="telerik"><section name="webAssets" type="Telerik.Web.Mvc.Configuration.WebAssetConfigurationSection, Telerik.Web.Mvc" requirePermission="false" /><sectionGroup>
<add name="asset" preCondition="integratedMode" verb="GET,HEAD" path="asset.axd" type="Telerik.Web.Mvc.WebAssetHttpHandler, Telerik.Web.Mvc" /> 
<telerik<webAssets useTelerikContentDeliveryNetwork="true" /> telerik> 
新版(Version Q1 2012)設定請看此→Telerik Extensions for ASP .NET MVC(Version Q1 2012)


3. 加入JavaScript file並註冊
以本文使用的2011 Q2為例,在C:\Program Files\Telerik\Extensions for ASP.NET MVC Q2 2011\Scripts內附""2011.2.712""資料夾,包括Telerik所用的全數JS,請將這個以日期命名的資料夾整份複製(也就是說Scripts資料夾內有2011.2.712資料夾)到WEB專案的Scripts資料夾。

註冊位置在所有component之後與< / body>之前
<%:Html.Telerik().ScriptRegistrar().Globalization(true).DefaultGroup(g => g.Combined(true).Compress(true)) %>
4. 加入CSS file並註冊
以本文使用的2011 Q2為例,在C:\Program Files (x86)\Telerik\Extensions for ASP.NET MVC Q2 2011\Content內附""2011.2.712""資料夾,包括Telerik所用的全數CSS,請將這個以日期命名的資料夾整份複製到WEB專案的Content資料夾。

註冊位置於head tag之間
<head><%: Html.Telerik().StyleSheetRegistrar().DefaultGroup(g => g.Add("telerik.common.css").Add("telerik.vista.css").Add("telerik.rtl.css").Combined(true).Compress(true))%> < /head>

完成上述步驟就可以安心服用Telerik各類花俏component