2014年7月29日 星期二

如何透過MSBuild 的過程中 COPY 檔案

最近有一個內部專案

我們想要利用 TFS 進行 自動化建置部署


所以開始動工吧!

我們新增一個組建

圖1


圖2

圖3

設定MSBuild的Config 如下:

/P:VisualStudioVersion=12.0 /P:DeployOnBuild=True /P:DeployTarget=MSDeployPublish /P:MsDeployServiceUrl=https://TESTWEB2:8172/msdeploy.axd /P:AllowUntrustedCertificate=True  /P:MSDeployPublishMethod=WMSvc /P:DeployIisAppPath=xxxxx   /P:CreatePackageOnPublish=True   /P:UserName=帳號/P:Password=密碼

接下來測試一下!
新增一個佇例一個新的組建。



完成後發現,程式是無法執行的原因是

缺少DLL檔

所以我們必需要針對MSBuild進行客製化,將我們需要的檔案移轉到我們要進行Deploy的Package的目錄,讓部署的時侯可以包含這些檔案。

但是如何客製化呢?
請這樣做

先卸載專案

編輯專案檔
請在文件最後面的地方加上


 
<ItemGroup  >
    <BinFiles Include="$(OutDir)**\*.dll" />
    <SourceFile Include="@(BinFiles)" />
 </ItemGroup>
  
<Target Name="AdditionalFilesForPackage" AfterTargets="CopyAllFilesToSingleFolderForMsdeploy">
    <Message Text="Test COPY Binaries Dll Start"/>
    <Copy SourceFiles="%(SourceFile.FullPath)" DestinationFolder="$(_PackageTempDir)\bin" Condition="$([System.String]::Copy(%(SourceFile.Filename)).Contains('關鍵字'))" />
    <Message Text="Test COPY Binaries Dll End"/></Target>

上面的行為如下:

我們定義二個 itemgroup 分別為:BinFiles 、SourceFile
BinFiles 我們定義的是MSBuild時,產生的路徑中全部的DLL檔案
SourceFile 我們定義的是使用 BinFiles的路徑

接下來 目標 Target 動作

我們定義了二個properties
 AfterTargets(在這個事件之後) CopyAllFilesToSingleFolderForMsdeploy 我們要執行下列動作
Name AdditionalFilesForPackage 這個是在LOG會顯示的TAG

Message: 顯示在LOG上的訊息
Copy:我們要COPY的檔案路徑、目標位置、條件
詳細內容請參考 :MSDN

以上動作就會將DLL COPY到PackageTempDir 讓MSDeploy進行封裝的動作。

比較困難的地方是語法的設定,因為MSDN上也沒有寫的非常的清楚。



2014年6月11日 星期三

Mask 遮罩延遲顯示的狀況

前一陣子碰到一問題!
先前寫過一個遮罩的功能,可以讓PG呼叫遮罩,然後進行AJAX處理

讓使用者等待畫面處理完成!

最近有人反應,他們使用後發現,部份的頁面會產生延遲顯示的狀況!!
也就是遮罩不會馬上顯示~

便開始追查問題

首先先用chrome來進行Timeline的錄製

發現當我按下儲存的時侯(click事件)

畫面就停住了,便產生了大量的GC javascript Heap高達 94MB

所以針對程式一看~

嗯,事出必有因,畫面的行為如下:

1、畫面上有近1000個checkbox
2、當按下送出的時侯會針對checkbox 進行取值,有選取的就加入陣例(透過Each的方式)

想了一下,這應該是因為進行了javascript的大量運算,所以遮罩完全跑不出來 UI的Thread就停了

所以便寫了一個測試程式:
1、產生一個簡單的For計算,j++
  var j = 0;
  for (var i = 0; i < 1000000000; i++) {//讓JS產生一個大量運算
   j++;
  }
 console.log(j);
2、透過Deferred 物件,保證執行完成
var dtd = $.Deferred(); // 新建deferred

3、透過setTimeout 讓畫面延遲5秒,直到動畫完成
 setTimeout(tasks, 5000); // 停頓5秒

這邊可能有人覺得奇怪,為何還要設定SetTimeout 5秒後才執行程式
我們已經使用了Deferred的物件了,應該可以保證事件執行完成
但是經過測試,我們確實是保證物件有執行了,但~因為我們後續馬上執行了一個大量運算
其實是會導致Browser偵測到一個JS佔用到太多CPU,而產生停止的訊息,所以導致動畫也無法完整執行完畢

失敗
               var dtd = $.Deferred(); // 新建deferred

                var show = function (dtd) {
                    var tasks = function () { //裡面請放置你的主程式!
                        funOpenLoadingMask(true);
                        dtd.resolve(); // deferred的狀態改變
                    };
                    tasks();
                    return dtd.promise();
                };

                $.when(show(dtd))
                .then(function () {
                    var j = 0;
                    for (var i = 0; i < 1000000000; i++) {//讓JS產生一個大量運算
                        j++;
                    }
                    console.log(j);
                }).done(funOpenLoadingMask(false))

成功
                 var show = function (dtd) {
                    funOpenLoadingMask(true);

                    var tasks = function () { //裡面請放置你的主程式!
                        var j = 0;
                        for (var i = 0; i < 1000000000; i++) {//讓JS產生一個大量運算
                            j++;
                        }
                        console.log(j);
                        dtd.resolve(); // deferred的狀態改變
                    };
              
                    setTimeout(tasks, 5000); // 停頓5秒
                    return dtd.promise();
                };
               
                $.when(show(dtd))
               .then(function () {
                    funOpenLoadingMask(false);
                });


附上檔案

2014年6月9日 星期一

Kendo UI Validator 的客制化顯示方式

接到一個需求,是需要將畫面上的Validation 進行客制化的設計!
一般來說,原本的 Kendo UI Validator 顯示畫面如下:


使用者的需求如下:
  1、發生問題輸入元件要變成紅色外框
  2、預設不顯示訊息
  3、要透過ToolTip的方式顯示
  4、當滑鼠移到元件上時,就顯示ToolTip

作法如下:

1、首先需要設定每一個INPUT的專屬訊息

<label class="required" for="fullname">Your Name</label>
<input class="k-textbox" id="fullname" name="fullname" placeholder="Full name" required="" type="text" validationmessage="Please enter {0}" />
<span class="k-invalid-msg" data-for="fullname"></span><!--  專屬的顯示 -->

2、撰寫CSS
   
            /*toolTip 的顏色*/
            .k-widget.k-tooltip {
                border-color: rgb(197, 197, 197);
                background-color: red;
                color: white;
            }

            /*讓textbox顯示有紅框,因為此方法為預設的行為。*/
            .k-invalid,
            .k-textbox.k-invalid {
                border: 1px solid #ee0101;
            }

            /*加入紅框給kendo ui的元件使用*/
            .UIBorderRed {
                border: 1px solid #ee0101 !important;
            }

            /*預設的errorTip樣式*/
            .errorTip {
                background-color: #ee0101;
                color: #fff;
                float: right;
                font-size: 12px;
                border: 2px solid #ddd;
                -moz-box-shadow: 0 0 6px #000;
                -webkit-box-shadow: 0 0 6px #000;
                padding: 4px 10px 4px 10px;
                border-radius: 6px;
                -webkit-border-radius: 6px;
                position: absolute;
                opacity: 0.87;
                display: none !important;
            }
           /*顯示的errorTip樣式*/
            .errorTipShow {
                background-color: #ee0101;
                color: #fff;
                float: right;
                font-size: 12px;
                border: 2px solid #ddd;
                -moz-box-shadow: 0 0 6px #000;
                -webkit-box-shadow: 0 0 6px #000;
                padding: 4px 10px 4px 10px;
                border-radius: 6px;
                -webkit-border-radius: 6px;
                position: fixed;
                opacity: 0.87;
                display: block !important;;
            }
3、建立主要程式
                
//主要的程式:驗證控制項
var validator = $("#tickets").kendoValidator({
                    rules: {
                        required: function (input) {
                             return PICRule(input);//客制化rule
                        }
                    },
                    errorTemplate: kendo.template( '<div class="errorTip k-widget k-tooltip k-popup"><div class="k-tooltip-content">#=message#</div><div class="k-callout k-callout-s"></div></div>')//樣版
                });
4、設計RULE
var PICRule = function (input){
                     var e = input.filter("[type=checkbox]").length && !input.is(":checked"),//如果是checkbox
                                    a = input.val();//輸入值
                            
                             //驗證規則,判斷是不是null或是不是一個物件,
                             var _ = function (t, e) { return t.length ? null != t[0].attributes[e] : !1 };
                             var ChangeBorder = function (Input) {
                                         return {
                                          Add: function AddClass() {

                                           var str = $(Input).parent();

                                            if (str != undefined && (str.hasClass("k-state-default") || str.hasClass("k-widget") )) {

                                            if ($(Input).parent().find('.k-state-default').length > 0) {
                                             // log($(Input));
                                            $(Input).parent().find('.k-state-default').addClass("UIBorderRed");
                                             } else {
                                                  //  log($(Input));
                                                  $(Input).parent().addClass("UIBorderRed");
                                             }

                                             }

                                                 if ($(Input).attr('type') == "checkbox") {
                                                                //log($(Input));
                                                                $(Input).parent().addClass("UIBorderRed");
                                                            }
                                                        },
                                                        Remove: function RemoveClass() {
                                                             //log($(Input));
                                                            $(Input).parent().find('.UIBorderRed').andSelf().removeClass("UIBorderRed");

                                                        }
                                                    }
                            };

                                var requiredChangeBorder = function (input, e, a) {
                                    var changeBorder = ChangeBorder(input);
                                    if (!("" === a || !a || e)) {
                                        changeBorder.Remove();
                                    }
                                    else {
                                        changeBorder.Add();

                                    }
                                };
                          requiredChangeBorder(input, e, a);
5、針對需要使用的資料進行綁定
                        //為kendo ui 客制化元件
                        $("form .k-widget").bind("mouseenter",function () {
                            var $inputElement = $(this).find(".k-invalid");
                            var position = $(this).position();
                            //log(position.top);
                            // log(position.left);
                            if($inputElement.length >0){//有該元素在
                              var elementName = "div[data-for='" + $inputElement.attr('name') + "']";
                                //log(elementName);
                                $(elementName).addClass('errorTipShow').css({"left" : position.left ,"top" : position.top - 25});
                            }
                        
                        }).bind("mouseleave",function () {
                            var $inputElement = $(this).find(".k-invalid");
                            var elementName = "div[data-for='" + $inputElement.attr('name') + "']";
                                $(elementName).removeClass('errorTipShow').removeAttr('style');
                        });

                        //為input類型的元件
                        $("form :input").bind("mouseenter",function () {
                            var $inputElement = $(this);
                            var position = $(this).position();
                             if (!$(this).parent().hasClass("k-widget") && !$(this).parent().parent().hasClass("k-widget")){//排除Kendo UI複合元件
                                //log($(this).parent());
                            
                                if($inputElement.hasClass("k-invalid")){//如果有錯誤發生
                                  var elementName = "div[data-for='" + $inputElement.attr('name') + "']";
                                   //log(elementName);
                                    $(elementName).addClass('errorTipShow').css({"left" : position.left ,"top" : position.top - 25});
                                }
                            }
                        }).bind("mouseleave",function () {
                            var $inputElement = $(this);
                            var elementName = "div[data-for='" + $inputElement.attr('name') + "']";
                                $(elementName).removeClass('errorTipShow').removeAttr('style');;
                        });

最後測試一下結果:
附上檔案

kendo UI TreeView 如果透過DataSource來綁定

這個簡單的Sample是用來說明,我們如果透過一個DataSource來Binding TreeView這個元件

並且綁定一個行為會在Consloe 顯示 我們點選的該筆資料訊息

首先我們需要一個DataSource


 var inline = new kendo.data.HierarchicalDataSource({
                    data: [
                        { categoryName: "StorageA",sprite:"folder", subCategories: [
                          { subCategoryName: "Wall Shelving",HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Floor Shelving",HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Kids Storage" ,HtmlAttributes:'{"url":"abc","title":"test"}'}
                        ] },
                        { categoryName: "Lights",sprite:"folder", subCategories: [
                            { subCategoryName: "Ceiling" ,HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Table" ,HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Floor",HtmlAttributes:'{"url":"abc","title":"test"}' }
                        ] },
                        {categoryName: "StorageB",sprite:"folder", subCategories: [
                            { subCategoryName: "Wall Shelving",HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Floor Shelving",HtmlAttributes:'{"url":"abc","title":"test"}'},
                            { subCategoryName: "Kids Storage",HtmlAttributes:'{"url":"abc","title":"test"}'},
                            {categoryName: "StorageC",sprite:"folder",
                             subCategories: [
                              { subCategoryName: "Wall Shelving" ,HtmlAttributes:'{"url":"abc","title":"test"}'},
                              { subCategoryName: "Floor Shelving" ,HtmlAttributes:'{"url":"abc","title":"test"}'},
                              { subCategoryName: "Kids Storage" ,HtmlAttributes:'{"url":"abc","title":"test"}'}
                            ] }
                        ] }
                    ],
                    schema: {
                        model: {
                            children: "subCategories"
                        }
                    }
                });
我們使用HierarchicalDataSource的DataSource 並且我們自定義了一個HtmlAttributes的屬性來存放該項目的URL與名稱
<script id="treeview-template" type="text/kendo-ui-template">
            
              # if (!item.subCategories) { #    
               <span class="opentab" data-options=#= item.HtmlAttributes # >#= item.subCategoryName #</span>            
              # } else { # 
                #: item.categoryName # 
              # }#        
</script>
透過一個kendo ui的template 綁定一個 data-options
 $("#treeview-right").kendoTreeView({
                    dataSource: inline,
                    dataTextField: [ "categoryName", "subCategoryName" ],
                    dataSpriteCssClassField: "sprite",
                     template: kendo.template($("#treeview-template").html())
                    });
                   
                  $(document).on("dblclick", ".opentab", function () {
                      var option = $(this).data("options");
                       console.log(option.title);
});
並且接下來就是進行一些初始化的設定,設定資料來源與欄位設定,最後記得要綁定double click的行為,讓資料會被選取顯示!



 附上檔案

如何讓 Kendo UI Grid 使用Numeric 設定為 ReadOnly

如何讓Kendo UI grid 裡面的欄位的Numberic變成readonly與設定成無小數點呢?

之前我們有寫一簡單的例子,現在拿來修改一下:

只需要簡單的在databound 裡面加上一個格式的設定與針對每一筆資料進行readonly的設定 
 
   dataBound: function(){
               // 請設置 format 的格式
               $(".numeric").kendoNumericTextBox({
                   format: "n0"
               });
                
                //針對每一個numeric設為 disable
                 $(".numeric").each(function(){
                   var numericid =$(this).attr("id");
                     if(numericid !== undefined){
                        $("#"+numericid).data("kendoNumericTextBox").enable(false);
                     }
               });
            },
  });



附上檔案

kendo ui grid 如何使用numeric 元件

開發單位尋問說如何讓grid的欄位透過JS的方式顯示numeric的元件
所以就簡單寫了一個SAMPLE
 
<!DOCTYPE html>
<html>
  <head>
    <title>KendoUI Test Page</title>
    <link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.common.min.css" rel="stylesheet" />
    <link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.default.min.css" rel="stylesheet" />
    <link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.dataviz.min.css" rel="stylesheet" />
    <link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.mobile.all.min.css" rel="stylesheet" />
    <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
    <script src="http://cdn.kendostatic.com/2013.2.716/js/kendo.all.min.js"></script>          
  </head>
  <body>
    <div id="example" class="k-content">
      <div id="grid"></div>
      <script id="slotsTemplate" type="text/x-kendo-tmpl"> 
        <input class="numeric" type="number" value="#= UnitsInStock #" step="1" />
      </script>
      
      <script>
        $(document).ready(function () {
          var crudServiceBaseUrl = "http://demos.kendoui.com/service",
              dataSource = new kendo.data.DataSource({
                transport: {
                  read:  {
                    url: crudServiceBaseUrl + "/Products",
                    dataType: "jsonp"
                  },
                  update: {
                    url: crudServiceBaseUrl + "/Products/Update",
                    dataType: "jsonp"
                  },
                  destroy: {
                    url: crudServiceBaseUrl + "/Products/Destroy",
                    dataType: "jsonp"
                  },
                  create: {
                    url: crudServiceBaseUrl + "/Products/Create",
                    dataType: "jsonp"
                  },
                  parameterMap: function(options, operation) {
                    if (operation !== "read" && options.models) {
                      return {models: kendo.stringify(options.models)};
                    }
                  }
                },
                batch: true,
                pageSize: 20,
                schema: {
                  model: {
                    id: "ProductID",
                    fields: {
                      ProductID: { editable: false, nullable: true },
                      ProductName: { validation: { required: true } },
                      UnitPrice: { type: "number" },
                      Discontinued: { type: "boolean" },
                      UnitsInStock: { type: "number", validation: { min: 0, required: true } }
                    }
                  }
                }
              });
          
          $("#grid").kendoGrid({
            dataSource: dataSource,
            dataBound: function(){
               $(".numeric").kendoNumericTextBox();
            },
            pageable: true,
            height: 430,
            toolbar: ["create"],
            columns: [
              "ProductName",
              { field: "UnitPrice", title: "Unit Price", format: "{0:c}", width: "100px" },
              { field: "UnitsInStock", title:"Units In Stock", template: kendo.template($("#slotsTemplate").html()) },
              { field: "Discontinued", width: "100px" },
              { command: ["edit", "destroy"], title: "&nbsp;", width: "172px" }],
            editable: "inline"
          });
        });
      </script>
    </div> 
 
  </body>
</html>

以上
附上檔案

2014年6月8日 星期日

Telerik UI for AspnetMVC Grid如何使用Number DateTime等編輯元件

在專案中碰到一個CASE,使用Telerik UI for AspnetMVC 當要編輯grid的內容時,如何使用Number 、 DateTime的元件呢?

其實使用的方法相當的簡單

當你安裝好telerik.ui.for.aspnetmvc

會有一個資料夾在你的VIEW資料夾中

然後只要針對你要使用的Model進行Attribute的設定即可

 
public class ProductViewModel
{
        [Editable(false)]
        [Key]
        [ScaffoldColumn(false)]
        [UIHint("String")]
        public int ProductID { get; set; }
        // The ProductName property is required
        [Required]
        public string ProductName { get; set; }
        // Use the Integer editor template for the UnitsInStock property
        [UIHint("Integer")]
        public short? UnitsInStock { get; set; }

        [UIHint("Decimal")]
        public decimal UnitPrice { get; set; }

        [DataType(DataType.Date)]
        public DateTime ProductDate { get; set; }
        [DataType(DataType.DateTime)]
        public DateTime ProductDateTime { get; set; }
}
應該會有人發如我們總共有使用二種方法。
1、[DataType(DataType.XXX)]
2、[UIHint("Integer")]

狀況區分如下:
[DataType(DataType.XXX)]
  這是微軟所提供的資料定義內容。
 
 
    // 摘要: 
    //     代表與資料欄位和參數相關聯之資料型別的列舉型別 (Enumeration)。
    public enum DataType
    {
        // 摘要: 
        //     表示自訂資料型別。
        Custom = 0,
        //
        // 摘要: 
        //     表示時間的瞬間,以一天的日期和時間表示。
        DateTime = 1,
        //
        // 摘要: 
        //     表示日期值。
        Date = 2,
        //
        // 摘要: 
        //     表示時間值。
        Time = 3,
        //
        // 摘要: 
        //     表示物件存在的持續時間。
        Duration = 4,
        //
        // 摘要: 
        //     表示電話號碼值。
        PhoneNumber = 5,
        //
        // 摘要: 
        //     表示貨幣值。
        Currency = 6,
        //
        // 摘要: 
        //     表示顯示的文字。
        Text = 7,
        //
        // 摘要: 
        //     表示 HTML 檔。
        Html = 8,
        //
        // 摘要: 
        //     表示多行文字。
        MultilineText = 9,
        //
        // 摘要: 
        //     表示電子郵件地址。
        EmailAddress = 10,
        //
        // 摘要: 
        //     表示密碼值。
        Password = 11,
        //
        // 摘要: 
        //     表示 URL 值。
        Url = 12,
        //
        // 摘要: 
        //     表示影像的 URL。
        ImageUrl = 13,
        //
        // 摘要: 
        //     表示信用卡卡號。
        CreditCard = 14,
        //
        // 摘要: 
        //     表示郵遞區號。
        PostalCode = 15,
        //
        // 摘要: 
        //     表示檔案上傳資料型別。
        Upload = 16,
    }
    那如果我們要使用的內容該定義沒有該怎麼處理呢?就透過下面的方法囉!

 [UIHint("Integer")]
    自行定義方法。


這樣畫面自然而然就會產生對應的UI編輯畫面了!