2016年12月1日 星期四

SSRS 報表使用上下標數字

是否有比較好的方法,在 Reporting Service 報表裡面使用上標(superscripts)、下標(subscripts)數字呢?

這個看似簡單的需求,目前的 Reporting Service 報表設計工具,似乎沒有很直覺簡單的處理方式。有人會建議,那就放圖片吧,這可行,但是圖片大小可能會因為報表的放大、縮小而失真,對工程師而言,要找到解析度剛好的圖片,其實不是一件容易的事。剩下比較常見的,就是透過 Unicode 的方式,取得上標或下標的數字,來完成我們的工作。

剛好最近的需求,是同時會用到數字的上標與下標,同時看到 SQLJason 裡的一篇文章,覺得很有價值。

他提出兩種方法。

第一種:是透過 chrw( ) 函數。把作者整理出來的圖表節錄如下,我們把 Superscript 的內容放到 chrw( ) 裡,就可以得到我們想要的上標了。



在報表裡,我們只需要再文字方塊的 Expression 裡面輸入:
="2"&chrw(178)

就可以得到 2 的平方。

※補充:20170120
如果還有其他想要加入的文字,可以透過 charmap.exe 打開字元對應表,並在其中找到想要的字符,此時要注意的有兩件事,第一是最上面的「字形」,要能夠正確顯示出內容,如果字型沒正確指定,則會出現亂碼。第二,是最下面的訊息框,它會顯示目前該字符的Unicode,但我們不能直接把它放到 chrw()裡面,因為他是 16 進位,所以要把它轉換成 10 進位的數字,可以到 convert 網頁把它轉換為 10 進位後,再放到 chrw()裡。



第二種:可以透過電腦的執行命令列,輸入 charmap.exe


就可以跳出字元對應表,這時,先在字型的下拉選項中挑選 Lucida Sans Unicode,接著你就可以在下方的字元清單中找到你想要的字,包含上標、下標的數字都有。


當你找到之後,就可以按選取,把他存放到「要複製的字元」,接著繼續挑,直到您滿意為止,最後再按「複製」。接著,就到報表設計工具,找到文字輸入方塊,點兩下後,直接用 Ctrl+V 貼上,這時,還要做一個動作,就是將文字輸入方塊的屬性裡的 FontFamily,也要設成:Lucida Sans Unicode。這樣,就可以正常顯示上下標文字了。



參考文章:
01.Subscripts and Superscripts in SSRS Reports

02.SSRS Reports – Displaying Superscripts and Subscripts

2016年11月29日 星期二

處理 ReportViewer 撐破版面的作法

在網頁上能夠即時產生出報表來瀏覽,其實還蠻方便的。程式開發者可以透過 ReportViewer 來完成這項功能。但是,如果發現要呈現的報表內容很長時,就會有頁面爆掉的風險。

舉例來說,我預期正常畫面應該長成下面這樣子。上面是報表內容,下面還有我的頁尾。


但是,結果卻是長成下面這樣子。


報表內容已經撐破了原先設定好的版面框架。這時,但有趣的,是 IE 瀏覽器會這樣,非 IE 的瀏覽器則不會。後來,在 ReportViewer 的設定裡,找到一個屬性:SizeToReportContent 。他預設是 false ,表示報表不會自動調整控制項來符合報表內容。所以,當我把他設成 True 之後,就可以解決版面被撐破的問題了。

2016年8月31日 星期三

曾被我們遺忘的台電

在 Cheers 雜誌讀到:

回溯台灣的百年電力史,第一章可從1887年(清光緒13年)寫起。清朝台灣巡撫劉銘傳邀請江浙仕紳集資白銀五萬兩,於台北市東門外設立「興市公司」(建設公司),隔年裝置小型蒸氣燃煤發電機,在丹麥電氣技師協助下,才在台北城內點亮了「台灣第一盞燈」。

接下來的幾個重要里程碑,包括1905年7月,台灣第一座水力發電所──龜山發電所完工,從此讓台北市區、艋舺及大稻埕地區都進入「有電時代」。而1934年(日據昭和9年)竣工的日月潭水力發電工程,更是推動「農業台灣」進入「工業台灣」的關鍵動力。日月潭水力發電廠是當時亞洲最大、世界第八的發電工程。光是日月潭第一發電所的發電量,即足以滿足1935年時,台灣電力株式會社的全系統實際尖峰負載,還整整多出38%的備載容量。

原來台灣電力的發展史,也是這麼的迷人。跨越清朝、日治、民國三朝,可真的稱的上是「三朝元老」了,同時也參雜了台灣百年來的政經情勢。拋開政客們偏頗的口號對立,坐下來好好欣賞這曾經有無數人犧牲奉獻所換得的產物,也是令人握緊拳頭、血淚交織啊!

2016年8月29日 星期一

使用 jQuery 完成 JSON 資料的傳遞

聽到要透過 JSON 來傳遞資料,心中不免冒出:那不是要寫很多行程式?不是還要引用 JSON 相關的 javascript 模組?不是還要... 總之,就是很煩就是了!

最近看了幾篇 JSON 相關的使用文章後,發現其實不困難,也還蠻簡潔的。或許有很多小細節的地方我還沒發現,但大致上目前會用到的功能,都已經可以達到了。

首先,要先建立一個模擬後端的程式,用來產生 JSON 資料,準備給前端使用,而內容就大概長得像下面這個樣子。


{
"title":"jquery 入門",
"price":"299",
"author":"paladin lee"
}


只是最後要回傳的時候,需將物件序列化成 JSON 格式再回傳,而也只需使用下面這方法就可以了。

System.Web.Script.Serialization.JavaScriptSerializer().Serialize(stringValue)

所以我的後端程式如下:

ser01.ashx

public void ProcessRequest (HttpContext context) {

    StringBuilder sb = new StringBuilder();
    sb.Append(@"{
    ""title"":""jquery 入門"",
    ""price"":""299"",
    ""author"":""paladin lee""
}
");

    //將 sb 物件序列化成JSON格式再回傳
    context.Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(sb.ToString()));
}


接下來要處理的,就是前端了。透過  jQuery 的 getJSON() 方法,可以讓我們輕鬆的接收回傳的 JSON 資料。再透過 $.each() 來一一處理每個項目的內容。

 $.each(data2, function (property, value) {

   //Do something...

 });


從後端所序列化的內容可知,回傳的資料裡面三筆,以第一筆為例, property 是 "title",value 則是 "jquery 入門"。這裡要特別注意,因為回傳的 JSON 資料目前只是被視為字串,要透過 $.parseJSON() 將這 JSON 字串轉為 JSON 物件才能進一步被我們使用。

前端完整的測試程式則如下所示:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .tb  
        {
            border-collapse:collapse ;                  
        }
        
        .tb th
        {
            border:1px solid black;
            padding:5px;
        }
        
        .tb td
        {
            border:1px solid black;
            padding:5px;
        }
        
    </style>
    <script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script>
        $(function () {
            
            $.getJSON("ser01.ashx", function (data) {

                var vTable = $("<table class='tb' border='1'></table>");
                var vItem01="";

                //convert JSON string, not an object
                var data2 = $.parseJSON(data);

                $.each(data2, function (property, value) {
                    vItem01 = vItem01 + "<tr><th>" + property + "</th><td>" + value + "</td></tr>";
                });                               

                $(vTable).append(vItem01);
                $(".div01").append(vTable);

            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">   
    <div class="div01">
    </div>
    </form>
</body>
</html>


而畫面結果就會長成這樣子:


這時,或許你可能會說,我其實想要的,是類似好幾本書的資訊,而不是單單某一本書的詳細內容ㄟ!這其實也不難,首先來產生後端的資料,其內容大概如下:
[
 {
 "title":"jquery 入門",
 "price":"299",
 "author":"paladin lee"
 },
 {
 "title":"html5 入門",
 "price":"199",
 "author":"Nikki"
 },
 {
 "title":"麻將",
 "price"":"99",
 "author"":"jason"
 }
]

同樣地,將他序列化後,就可以直接送出去了。

server02.ashx

public void ProcessRequest (HttpContext context) {
 StringBuilder sb = new StringBuilder();
 sb.Append(@"[
 {
 ""title"":""jquery 入門"",
 ""price"":""299"",
 ""author"":""paladin lee""
 },
 {
 ""title"":""html5 入門"",
 ""price"":""199"",
 ""author"":""Nikki""
 },
 {
 ""title"":""麻將"",
 ""price"":""99"",
 ""author"":""jason""
 }
 ]
 ");
 //將 sb 物件序列化成JSON格式再回傳
 context.Response.Write(new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(sb.ToString()));
}


至於前端的部份,我們則是透過兩次的 $.each() 來把回傳的 JSON 資料解析出來。
$.each(data, function () { 
 //處理每一筆的資料
 $.each(this,function(property, value){
  //處理每一個欄位的資料
 });                    
});



完整前端程式如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .tb  
        {
            border-collapse:collapse ;                  
        }
        
        .tb th
        {
            border:1px solid black;
            padding:5px;
        }
        
        .tb td
        {
            border:1px solid black;
            padding:5px;
        }
        
    </style>
    <script src="js/jquery-1.10.2.min.js" type="text/javascript"></script>
    <script>
        $(function () {

            // test ser01
            $.getJSON("server02.ashx", function (data) {

                var vTable = $("<table class='tb' border='1'></table>");
                var vItem01 = "";

                //convert JSON string, not an object
                var data2 = $.parseJSON(data);

                //header
                vItem01 += "<tr><th>title</th><th>price</th><th>author</th></tr>";                               

                $.each(data2, function () { 
                    vItem01+="<tr>";
                    $.each(this,function(property, value){
                        vItem01+="<td>"+value+"</td>";
                    });
                    vItem01 += "</tr>";                    
                    
                });

                $(vTable).append(vItem01);
                $(".div01").append(vTable);

            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div class="div01">
    </div>
    </form>
</body>
</html>


希望透過以上簡單範例,會讓你對於 jQuery 與 JSON 資料傳遞會有更親切的感覺。

2016年8月26日 星期五

用Aspose替 PDF 加上底圖


如果一張獎狀的 PDF 檔,內容長得如上圖,會不會覺得哪裡怪怪的?沒錯,少了「框線」。

接下來想要透過 Aspose 工具,來把這張 PDF 檔加上框線。而這原理,可以簡單的想成把 PDF 檔案加上底圖。

首先,先找好一個有框的底圖。大概像下面這樣:

BackGround.png
接著,就可以透過 Aspose 的 Document 物件,來取得原先的 PDF 檔案。這時候的 Document ,可以視為 PDF 的代表。
Document pdfDocument = new Document("PDF來源");

一份 PDF 檔案,可能會有很多頁(Page),所以,透過 Page 物件,可以讓我們指定要控制第幾個頁面。而這裡的頁面標示,則是從 1 開始算起。
Page pdfPage = pdfDocument.Pages[1];

ImageStamp 則是接下來的主角,他就好比我們的橡皮圖章一樣,待會會蓋在每個頁面上。若用圖層的觀點來看,就有所謂的上下之分,這時,可以利用 ImageStamp 的 Background 屬性來決定,決定這個橡皮圖章的內容是要完全蓋過原先的內容,還是只是當個背景。如果需要微調 ImageStamp 的大小,則有 Width、Height 可以設定。
ImageStamp imgStamp = new ImageStamp(strStampFullPath);


完整程式可以簡述如下:
class PdfFunction
{
    public void AddBackGroundIMG(string PDFPath)
    {

        string setupFile = "BackGround.png";

        //取得執行路徑
        string strExecPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        //取得檔案的完整路徑
        string strStampFullPath = string.Format("{0}\\{1}", strExecPath, setupFile);

        //設定 license
        Aspose.Pdf.License license = new Aspose.Pdf.License();
        license.SetLicense(string.Format("{0}\\{1}",strExecPath , "Aspose.Total.lic"));


        //透過 Aspose 的 Document 物件,來取得原先的 PDF 檔案
        Document pdfDocument = new Document(PDFPath);
        Page pdfPage;
                       

        for (int i = 0; i < pdfDocument.Pages.Count; i++)
        {        
            //Aspose 是從 1 開始算的
            pdfPage = pdfDocument.Pages[i + 1];

            //取得外部圖片並指定為 ImageStamp 格式
            ImageStamp imgStamp = new ImageStamp(strStampFullPath);

            //將加入的圖片指定設為背景
            imgStamp.Background = true;

            //設定圖片長寬
            imgStamp.Width = 850;
            imgStamp.Height = 600;

            //將底圖加入到 PDF 頁面
            pdfPage.AddStamp(imgStamp);

        }


        // 產出新檔案
        pdfDocument.Save(string.Format("{0}\\{1}", strExecPath, "out.pdf"));

    }
}


要使用時,則是如下呼叫:
class Program
{
 static void Main(string[] args)
 {
  string setupFile = "award.pdf";

  //取得執行路徑
  string strExecPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  //取得檔案的完整路徑
  string strStampFullPath = string.Format("{0}\\{1}", strExecPath, setupFile);

  PdfFunction oP = new PdfFunction();
  oP.AddBackGroundIMG(setupFile);
 }
}


最後,有框的獎狀就會像下面這樣子:




Ref:
01:how to insert a watermark image into existing .pdf

2016年8月24日 星期三

透過 BlockUI 產生遮罩效果


當預期後端 Server 的處理時間會很久時,總是希望讓使用者知道系統還活著,只是正在處理中。這時,就會希望有個「遮罩」效果,讓背景呈現灰階、甚至放一個動態 .gif 圖檔來表示。

網路上蠻多推薦 BlockUI 的文章,自己實際去練習,發現還蠻容易上手的。

首先,必須先把會用到的 .js 抓回來。 (  jQueryBlockUI )
然後在網頁上引用他們。


    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.blockUI.js" type="text/javascript"></script>


而使用 BlockUI 的方法則是:
$.blockUI({ message: '<div>處理中! </div>' });  

不過,為了讓等待時不枯燥無聊,所以另外放了一個會動的 .gif 圖檔。可以到 ajaxload 去客製化自己喜歡的動態圖檔再下載使用。


完整程式如下:

Test.aspx

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.blockUI.js" type="text/javascript"></script>
    <style>
        .divAlert 
        {
            color:Red;
            font-size:18px;
            line-height:25px;            
            vertical-align:middle;
        }
    </style>
    <script>
        $(function () {
            $("input[id$=btn01]").click(function () {
                $.blockUI({ message: '<div class="divAlert">處理中! &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img width="20px" src="./images/loader-red.gif"></img></div>' });  
            });

        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:Button ID="btn01" runat="server" Text="點選" onclick="btn01_Click" />
    
       
        </div>
    </form>
</body>
</html>



Test.aspx.cs

using System.Threading;


protected void btn01_Click(object sender, EventArgs e)
{
    //讓程式跑久一點... 5 秒
    Thread.Sleep(5000);        
}

參考:
01:ajaxload
02:BlockUI Plugin - 功能完善的頁面、訊息遮罩
03:使用 jQuery 的blockUI 顯示 讀取中

2016年7月12日 星期二

泛型 generic

好久好久以前,學習 C# 應該有聽過 ArrayList 這個類別。還蠻好用的,不僅僅可以把字串丟進去,數字也可以,自訂的類別也可以,甚至...你要混搭,混著丟也可以。

ArrayList al = new ArrayList();
al.Add("字串");
al.Add(66);
al.Add(new Student("1","paladin"));

如同上面的例子,似乎什麼樣的型別,都可以放進 ArrayList,主要是因為 ArrayList 把裡面所有的內容都包裝(Boxing)成「物件(Object)」型別了,換句話說,ArrayList 裡面放的,都是 Object 型別。像這樣的特性,我們又把他歸類為:非泛型集合(nongeneric collection)。可想而知,這種非泛型集合,雖然可以讓你隨性的把任何東西都丟進去,但當你要從裡面把資料取出來時,就不能保證拆解(Unboxing)時,裡面的型別是否就是你所預期的。當然,程式在編譯時,也不會幫你進行型別檢查,往往要等到程式執行時,才會出現所謂的 Run Time Error。聽起來,使用這個非泛型集合很像很「」,對不對?沒錯,所以我們會稱非泛型集合裡面的成員為「弱型別」(Weak Typing)。

既然有所謂的「弱」,自然就會有跟它相對應的「強」。強型別 (Strong Typing) 的特性,當然就具備了以下的特徵【Ref.01】:

1.所有的變數的資料型態,在編譯時都要被知道。
2.嚴格的落實資料型態必須相符規則。例如,字串不能轉成數字。
3.所有型別轉換的錯誤,會導致編譯錯誤。也就是說,型別錯誤就無法編譯成功。

強型別具備上述特徵,自然就有了下面的好處【Ref.02,03】:

1.讓 IntelliSense 能夠支援變數。這能讓您在輸入程式碼時看到變數的屬性及其他成員。
2.可以利用編譯器型別檢查,這能找出可能因錯誤 (例如溢位) 而在 Run Time 失敗的陳述式。這也能夠偵測在不支援變數的物件上所進行的方法呼叫。
3.執行程式碼的速度較快。

相對於非泛型集合的,就是泛型集合( generic collection )【Ref. 04】,而裡面所放的成員,則都是屬於強型別。這裡的代表人物 List,於是登場了。這個 T ,代表了某一種資料型別,可以是:int,string...或者是使用者自訂的一個類別。



參考:

01.What is strong-typing versus weak-typing? Which is preferred? Why?
02.Efficient Use of Data Types 
03.何謂「強型別」(Strong Type)
04.When to Use Generic Collections



2016年6月6日 星期一

只抓片段的 .load()

在 jQuery 中,可以透過 .load() 來抓取其他頁面的資料。

一般來說,我可能只會用到  $("#divContent").load("pageB.htm");

但最近發現,.load(url)  裡的 url ,除了可以填入網址外,也可以透過類似 jQuery 的 select 條件,對 url 的內容進行條件篩選。

舉例來說,$("#divContent").load("pageB.htm div");   ,就可以抓取 pageB.htm 的內容,同時過濾資料,只取有 div 的內容。

同樣的,$("#divContent").load("pageB.htm #myDiv"); ,則是只抓取 pageB.htm 裡 ID 為 myDiv 的內容。

假設 pageB.htm 的內容如下:

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    AAAAA<br />
    BBBBB
    </div>
    <div id="myDiv">
    CCCCC
    </div>
    </form>
</body>
</html>

那 $("#divContent").load("pageB.htm #myDiv");  的結果,就只會出現 :CCCCC   了!

參考:
01..load()
02.loading page framents with Jquery AJAX

Bootstrap 上的 Carousel 輪播

每個輪播元件,其實都各有特色。

而 Bootstrap 自己也有提供一個輪播元件,效果還蠻不錯的。


提供了上下頁切換、索引切換、圖片說明等功能。

<!DOCTYPE html>
<html>
<head>
   
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>照片輪播</title>
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <!-- Latest compiled and minified JavaScript -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

 <meta charset="utf-8" />
</head>
<body>
    <div  id="photoCarousel" class="carousel slide" data-ride="carousel" data-interval="3000">
        <!-- 瀏覽控制器-->
        <ol class="carousel-indicators">
            <li data-target="#photoCarousel" data-slide-to="0" class="active"></li>
            <li data-target="#photoCarousel" data-slide-to="1"></li>
            <li data-target="#photoCarousel" data-slide-to="2"></li>
        </ol>


        <!-- 建立相片清單-->
        <div class="carousel-inner">
            <div class="item active">
                <img src="http://www.discuss.com.hk/attachment.php?aid=2324556&nothumb=yes" />
                <!--加上照片說明-->
                <div class="carousel-caption">
                    <h3>照片說明</h3>
                    <p>這是我們第一次牽手的地方</p>
                </div>
            </div>
            <div class="item">
                <img src="http://image5.tuku.cn/pic/wallpaper/fengjing/zhenhanweimeideziranjingguanbizhi/007.jpg"  />
                <!--加上照片說明-->
                <div class="carousel-caption">
                    <h3>照片說明</h3>
                    <p>這是我們第一次相見的地方</p>
                </div>
            </div>
            <div class="item">
                <img src="http://www.bz55.com/uploads/allimg/120813/1-120Q3092433.jpg" />
                <!--加上照片說明-->
                <div class="carousel-caption">
                    <h3>照片說明</h3>
                    <p>這是我們第一次約會的地方</p>
                </div>
            </div>
        </div>

        <!--上下一張控制-->
        <a class="left carousel-control" href="#photoCarousel" data-slide="prev">
            <span class="glyphicon glyphicon-chevron-left"></span>
        </a>
        <a class="right carousel-control" href="#photoCarousel" data-slide="next">
            <span class="glyphicon glyphicon-chevron-right"></span>
        </a>

    </div>
</body>
</html>



Carousel 輪播元件的使用,只要在 div 將 class 指定為 carousel slide 就可以了。data-ride="carousel" ,則是讓 Carousel 在頁面上一載入就開始執行輪播。data-interval="3000" 則是設定每3秒換一張圖片。

《瀏覽控制器》,這指的是圖片上會出現的小白點、小圈圈,如果你有四張圖片要輪播,就會有四個小白點。他是透過 <ol> 、 <li> 來完成的。ol 頁籤需要加上 carousel-indicators 樣式類別,而 li 頁籤,則是需要指出 Carousel 元件 ID : data-target="#photoCarousel",輪播順序:data-slide-to="0" ...,而第一個 li 頁籤還需加上  class="active" ,表示是從這裡開始的。

《建立相片清單》,則是實際用來定義照片來源集合的地方。他是由兩層 div 來完成。第一層是容器,第二層則是個別每一張圖片的定義。首先看第一層,僅需加上樣式類別 carousel-inner 即可。接著看第二層,則是加上樣式類別 item,不過,第一個圖片需額外多加一個  active 的樣式類別。

在第二層的 div 裡,可以看到 <img> 頁籤,他的 src 屬性,就是用來指出照片來源 URL。如果還需要對照片加上說明的話,可以在此多加一個具有樣式類別 carousel-caption 的  div:<div class="carousel-caption"> ,在這 div 裡,可以顯示照片說明。

《上下一張控制》,則是在照片的左右邊各產生一個按鈕,讓你可以操作上一頁、下一頁的動作。data-slide="prev" 、data-slide="next" 分別指出了動作行為,而按鈕的形狀,則是用 <span> 以樣式類別 glyphicon glyphicon-chevron-left、glyphicon glyphicon-chevron-right 所產生的圖形來表示。


參考:

01:Bootstrap Carousel Plugin
02:網頁程式設計的16堂課: HTML5‧CSS3‧JavaScript ‧jQuery‧AJAX‧Bootstrap‧Google Maps

2016年6月2日 星期四

讓 Bootstrap 製作的 NavBar 能夠永遠出現在螢幕的上方

當畫面內容漸多時,我們就會透過捲軸來捲動頁面,而原先放在頁面最上面的 NavBar 也就會因為往下捲動而消失。為了讓 NavBar 可以不因捲軸的捲動而消失,永遠停在最上面,其實還蠻簡單的,只要  nav  多加一個樣式 navbar-fixed-top 就可以達到。

<nav class="navbar navbar-default navbar-fixed-top">

但過沒多久,你就會發現,加上 navbar-fixed-top 後,原先的 NavBar 很像浮起來似的,永遠固定在螢幕上面,但麻煩的是,我原先設計在 NavBar 下方緊鄰的內容,會因為被 NavBar 遮蔽而永遠看不到。


正如上圖,項目a ~ 項目c,都會一直被遮住。這問題,我在 twitter bootstrap navbar fixed top overlapping site 找到了答案。只需要將 body 的樣式,加上  padding-top: 70px; 就可以解決。

程式碼如下:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MyPage.aspx.cs" Inherits="bot02.MyPage" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <!-- Latest compiled and minified CSS -->
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <!-- Latest compiled and minified JavaScript -->
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

    <style> body { padding-top: 70px; }</style>
</head>
<body>
    <form id="form1" runat="server">
        

        <nav class="navbar navbar-default navbar-fixed-top">
           
                <div class="navbar-header">
                    <a href="#" class="navbar-brand">正妹快搜網</a>
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNav">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                </div>
            
                <div id="myNav" class="collapse navbar-collapse">
                    <ul class="navbar-nav nav">
                        <li><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>
                        <li><a href="#"><span class="glyphicon glyphicon-heart"></span> Tour</a></li>
                        <li><a href="#"><span class="glyphicon glyphicon-picture"></span> Photography</a></li>
                        <li><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-info-sign"></span> About US <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="#"><span class="glyphicon glyphicon-plane"></span> 經營理念</a></li>
                                <li><a href="#"><span class="glyphicon glyphicon-user"></span> 攝影團隊</a></li>
                                <li class="divider"></li>
                                <li><a href="#"><span class="glyphicon glyphicon-envelope"></span> 加入我們</a></li>
                            </ul>

                        </li>
                    </ul>
                </div>
           
        </nav>
        <div >
            項目 a<br />
            項目 b<br />
            項目 c<br />
            項目 d<br />
            項目 e<br />
            項目 f<br />
            項目 g<br />
            項目 h<br />
            項目 i<br />
            項目 j<br />
            項目 k<br />
            項目 l<br />
            項目 m<br />
            項目 n<br />
            項目 o<br />
            項目 p<br />
            項目 q<br />
            項目 r<br />
            項目 s<br />
            項目 t<br />
            項目 u<br />
            項目 v<br />
        </div>
    </form>
</body>
</html>



參考:

01:twitter bootstrap navbar fixed top overlapping site

利用 Bootstrap 建立簡易的 NavBar


雖說用來製作 NavBar 的元件其實有很多,但會想試著使用 Bootstrap,實在是他太火紅了,簡直就像是一位專業的美編在你身邊,專業到連他說什麼我都聽不懂,因為他幫我定義好的東西太多了,讓我不得不好好一邊 K文件一邊做筆記。

首先在自己的頁面上,需要先將會引用到的 .css、 .js  加上去,只不過,為了讓手機使用者在瀏覽頁面時不要看得太吃力,所以加上了 @media 來設定 viewport,頁面的開始,就從下面開始說起:
<head runat="server">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title></title>

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>

   
</head>

第一個 <meta http-equiv="X-UA-Compatible" content="IE=edge"> ,是為了讓 IE 能夠相容而做的設定。

第二個 <meta name="viewport" content="width=device-width, initial-scale=1"> ,則是用來設定 ViewPort,我指定他的寬度跟我設備的寬度一樣,預設的縮放則是設為 1 ,表示使用原尺寸 100%。initial-scale 可以設定從 0 ~ 10.0 的範圍,數值小於 1 表示縮小,大於 1 表示放大。

接下來,則是分別引用了 bootstrap 的 css、jQuery 的 js 以及 bootstrap 的 js 。

而 NavBar 的主角,則是使用  <nav></nav> 來登場。而這裡要注意的,則是有一大堆的 class 要慢慢分清楚並對應到正確的元件上來使用。

這個 <nav class="navbar navbar-default"> ,我們指出是要使用 navbar 的樣式類別,而且是還額外要用 navbar-default 這樣式。

為了讓手機這類小螢幕的裝置可以清楚的顯示,bootsrtap 讓我們可以在當畫面寬度小於 768px 時,自動把 NavBar 以垂直折疊的方式來顯示。


所以我們要用一個 div 來定義所謂的 navbar-header 。

<div class="navbar-header">
 <a href="#" class="navbar-brand">正妹快搜網</a>
 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNav">
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
 </button>
</div>

<a href="#" class="navbar-brand">正妹快搜網</a> ,是我們看到的 Navbar 標題。而後面的 button ,則是透過 三條 橫線來表示,這裡的橫線則是使用 span 並指定他的 class 就可以使用 bootstrap 已經幫我們定義好的樣式直接使用。

關於這個 button 還有幾個可以說明。
class="navbar-toggle",表示這個 button 的樣式是使用 navbar-toggle
data-toggle="collapse",表示按鈕按下的動作是屬於「折疊」的方式
data-target="#myNav",表示這個按鈕對應到表單的哪個元件 ID,#myNav 是接下來要介紹的元件ID。


<div id="myNav" class="collapse navbar-collapse">
 <ul class="navbar-nav nav">
  <li><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>
  <li><a href="#"><span class="glyphicon glyphicon-heart"></span> Tour</a></li>
  <li><a href="#"><span class="glyphicon glyphicon-picture"></span> Photography</a></li>
  <li><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-info-sign"></span> About US <span class="caret"></span></a>
   <ul class="dropdown-menu">
    <li><a href="#"><span class="glyphicon glyphicon-plane"></span> 經營理念</a></li>
    <li><a href="#"><span class="glyphicon glyphicon-user"></span> 攝影團隊</a></li>
    <li class="divider"></li>
    <li><a href="#"><span class="glyphicon glyphicon-envelope"></span> 加入我們</a></li>
   </ul>

  </li>
 </ul>
</div>

現在登場的,則是重要的角色,因為 NavBar 裡的所有項目,都是定義在這裡。因為要寫很多,所以很重。

首先,使用  div ,而他的 ID ,就姑且取名為 myNav ,也就是上面提到,要用 #myNav 要找得對象。他則是採用  collapse 樣式類別,額外加上 navbar-collapse 樣式。這個 navbar-collapse 樣式,就是讓 NavBar 在螢幕寬度小於 768px 時會被隱藏的關鍵。

選單清單可以是巢狀式多層的,每一層則是透過  <ul> <li></li> ... </ul> 來完成。

在範例的第一層裡,<ul class="navbar-nav nav"> ,指出 navbar 元件選單的樣式類別是 navbar-nav ,且額外要加上 nav 樣式。

而在 <li><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>,是把每個清單的項目都放在個別的 li 元件中,超連結 <a href="#"> ,裡面的 href 屬性則是定義了該選單被按下去之後,要跳轉的頁面。

這裡有個很特別的地方,就是 bootstrap 事先將很多常用的小圖 icon 都定義好了,你可以到 glyphicons 找到這些圖示。要使用的時候,僅僅只是使用一個 span 元件,然後指定他的樣式類別為 glyphicon ,而額外的樣式定義,就是那些圖示的名稱。

在一個具有子選單的 li ,它會長成這樣 <a href="#" class="dropdown-toggle" data-toggle="dropdown"> ,class="dropdown-toggle" 表示他的樣式類別是  dropdown-toggle , data-toggle="dropdown" 則表示這是一個下拉選單。

<span class="caret"></span> 則是透過 bootstrap 所定義好的 caret 樣式類別套用到 span 裡, caret 可以讓我們產生一個到三角形的圖示。一般在選單中,也是透過這個倒三角形表示選單裡還有子選單。

第二層的選單,出現了第二個 ul 了。<ul class="dropdown-menu">,他使用的樣式類別為  dropdown-menu 。裡面的 li 基本上也是跟上一層的使用方法是一樣的。唯獨多了一個 <li class="divider"></li>,他主要也是利用 bootstrap 事先定義好的樣式類別 divider 達到在選單中呈現「分隔線」的效果。

完整程式碼如下:


<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="MyPage.aspx.cs" Inherits="bot02.MyPage" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title></title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
  
</head>
<body>
    <form id="form1" runat="server">        

        <nav class="navbar navbar-default">
           
                <div class="navbar-header">
                    <a href="#" class="navbar-brand">正妹快搜網</a>
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#myNav">
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                        <span class="icon-bar"></span>
                    </button>
                </div>
            
                <div id="myNav" class="collapse navbar-collapse">
                    <ul class="navbar-nav nav">
                        <li><a href="#"><span class="glyphicon glyphicon-home"></span> Home</a></li>
                        <li><a href="#"><span class="glyphicon glyphicon-heart"></span> Tour</a></li>
                        <li><a href="#"><span class="glyphicon glyphicon-picture"></span> Photography</a></li>
                        <li><a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="glyphicon glyphicon-info-sign"></span> About US <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="#"><span class="glyphicon glyphicon-plane"></span> 經營理念</a></li>
                                <li><a href="#"><span class="glyphicon glyphicon-user"></span> 攝影團隊</a></li>
                                <li class="divider"></li>
                                <li><a href="#"><span class="glyphicon glyphicon-envelope"></span> 加入我們</a></li>
                            </ul>

                        </li>
                    </ul>
                </div>           
        </nav>

    </form>
</body>
</html>


參考:

01:網頁程式設計的16堂課: HTML5‧CSS3‧JavaScript ‧jQuery‧AJAX‧Bootstrap‧Google Maps
02:https://getbootstrap.com/components/

2016年5月30日 星期一

LINQ 讀取 ADO.Net DataTable 內容

能夠將我們習慣的 DataTable 透過 Linq 來進行查詢,是一件很幸福的事情。基本上,只要記得兩個語法就可以針對  DataTable 來操作。

第一個是:把 DataTable 轉為 IEnumerable<T>
使用 AsEnumerable() 來完成

第二個是:把 Linq 查詢的結果存成 DataTable。
使用 CopyToDataTable<DataRow>() 來完成


可以透過下面範例來練習:

//抓取 DataTable dtDetail 的資料
DataTable dtDetail=oT.getDataById(strID).Tables[0];

//透過 AsEnumerable() 將 DataTable 轉為 IEnumerable<T> 格式
IEnumerable<DataRow> queryDetail = from d in dtDetail.AsEnumerable()
where int.Parse( d.Field<string>("sud_salesdate") ) > int.Parse("20160101")
select d;

//將查詢結果存成 DataTable
DataTable dtResult = queryDetail.CopyToDataTable<DataRow>();

2016年5月11日 星期三

Reporting Service 報表升級的問題

過去曾用過 VS2008 開發過好幾支 Reporting Service Server Report,因為有需求將這些報表改成 Local Report,而開發工具則是升級為 VS2010。比對了這兩個版本的差異,是副檔名不同,VS2008 的副檔名是 *.rdl ,VS2010 的副檔名則是 *.rdlc。所以,只要在副檔名加個 c 應該就可以了吧!

於是,我將 Certificate_Test.rdl 複製到 VS2010 的開發資料夾,再把檔名改成  Certificate_Test.rdlc, 並用 VS2010 去開啟它。


看起來,還好嘛,就讓他自己去轉換就好,於是按了「確定」!


看到「One or more errors encountered while loading the designer. The errors are listed below.」錯誤訊息,然後   就  ...   傻住了...   真的傻住了!

透由 Polly 的協助,參考了一篇由 prakash rao 所發表的文章「Microsoft Report Designer : Do you want to convert this report to RDLC 2008 format? Please click OK to proceed or Cancel to open it in the XML editor. 」,一步一步完成了轉換工作。

首先,從傻住的頁面開始,點選 「Edit Code」,就可以看到用 XML 所表示的內容。其實,不管是 *.rdl 也好, *.rdlc 也好,報表的內容都是用 XML 來定義的。在報表升級開發工具升級的過程中,難免會新增或刪除了 XML 的標籤或元素。先看到的,就是升級後被刪除的 「ReportSection」與「ReportSections」,可以用 Ctrl+F 打開搜尋視窗,找到那兩個標籤,因為每個標籤同時都會有起始與結束,所以都要刪除。



然後,再到最前面的第二行 Report xmlns



將它改成:

<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">


最後就按「存檔」。接著把剛剛編輯的報表都關掉,然後重新點選 Certificate_Tesst.rdlc,就可以看到正常的報表了。

因為我改成使用 Local Report 的方式,原先要傳給 Server Report 的參數已經不需要了,要記得到 Report Data 裡的 Parameters 刪除。


此外,因為我已不再使用 DataSource1,所以也順便刪除,然後在新增一個 DataSet。你可能會發現, DataSource1 竟然刪不掉,別擔心,點開你的 DataSource1,會發現裡面還會有 DataSet,先把裡面的所有 DataSet 都刪掉,然後就可以刪除 DataSource1 了。


參考:
01:Microsoft Report Designer : Do you want to convert this report to RDLC 2008 format? Please click OK to proceed or Cancel to open it in the XML editor. 

2016年5月4日 星期三

LocalReport 報表合併後變成空白

我使用了 Local Report 產生了好幾張 PDF  報表,接著想要將他們合併成一份報表。這時,我選用了 Aspose 這工具,多年前,我曾經用過他,一直合作愉快。

「昨是而今非」,是今天最好的註解。透過 Aspose 合併後的 PDF 檔案,裡面竟然是空白的,我發誓,還沒合併前,每一份 PDF 的確是有資料的啊!

原來,我的 PDF 是透過 VS2010 所產生的,報表的產生語法如下:


byte[] tBytes = viewer.LocalReport.Render(pType, null, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);


Render() 裡的第二個參數,本應該放 deviceInfo,我原先覺得很像沒什麼好設定的,於是就簡單放了 null。在「PDF Sharp can't handle SQL Server 2008 PDF reports」文章中提到,Reporting Service 2008 之後,開始有了 HumanReadablePDF 這個參數設定,指示是否 PDF 匯出時應該被壓縮,使得檔案更容易閱讀,預設值為 False。因為我把 devideInfo 設為 null,所以 HumanReadablePDF = false。這個致命的關鍵設定,造成讓 Aspose 在合併 PDF 時,無法正確的取得原先 PDF 內容。所以,要手動去定義 HumanReadablePDF,並將它設為 true。

透過下面語法,就可以完成:
string devInfo = @"<DeviceInfo><HumanReadablePDF>True</HumanReadablePDF></DeviceInfo>";
byte[] tBytes = viewer.LocalReport.Render("PDF", devInfo, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);




參考:

01:PDF Sharp can't handle SQL Server 2008 PDF reports
02:[SQL Server 2008R2][SSRS] URL Access 報表轉譯格式設定(二)

2016年5月3日 星期二

使用 VS2010 在 Console Application 下 產生 LocalReport

01.增加參考。包含

Microsoft.ReportViewer.WebForms (Ver.10.0)
Microsoft.ReportViewer.Common (Ver.10.0)

※ 注意,ReportViewer 版本要選 10.0

System.Web (Ver 2.0)
System.Web.Extensions (Ver 3.5)




02.建立一個空白報表,取名為 Report1.rdlc。


03.建立一個 DataSet,取名為 dsTest.xsd


04.在 dsTest.xsd 建立一個查詢。選擇 Add → TableAdapter




建立一個新的 DB 連線資訊。


這裡是說,剛剛的連線字串因為有帳號密碼,屬於敏感資料,是否要在連線資訊裡顯示,選擇「是」。


針對剛剛的連線,取個名字。


挑選要查詢的方式,因為待會要自己寫 SQL,所以選「Use SQL statements」


這裡只是做個簡單的查詢指令,然後可以直接按「Finish」來完成。


存檔後,先重先編譯一下專案。Build → ReBuild Solution。

05.回到 Report1.rdlc。到 ReportData ,如果看不到 ReportData,則到 View → Report Data 可以找到。


選擇 New→DataSet


在 Data Source 挑選 dsTest,然後點選 「OK」


將 DataSet1 的 CustCName 拖拉到 報表 內文中,然後存檔。



有個小地方別忘了,就是將 Report1.rdlc 屬性裡的  Copy  to Output Director 設為 「Copy Always」。這樣,當程式被編譯時,自動會將報表複製到 BIN 資料夾。




06. 參考了這篇「[C#]透過ReportViewer將報表另存成檔案」,將 Program.cs 程式改寫如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Reporting.WebForms;
using System.Data.SqlClient;
using System.Data;
using System.IO;


class Program
{
 static void Main(string[] args)
 {
  ExportReport("PDF");
 }

 public static void ExportReport(string pType)
 {

  Microsoft.Reporting.WebForms.Warning[] tWarnings;
  string[] tStreamids;
  string tMimeType;
  string tEncoding;
  string tExtension;


  // Setup the report viewer object and get the array of bytes
  ReportViewer viewer = new ReportViewer();
  viewer.ProcessingMode = ProcessingMode.Local;
  viewer.LocalReport.ReportPath = "Report1.rdlc";

  string DBConnection = @"DATABASE=CarISC;Server=140.11.1.1,5555;User ID=account;Password=pwd";
  string sql = @"select top 1 * from Customer";
  SqlConnection conn = new SqlConnection(DBConnection);
  SqlCommand SqlCmd = new SqlCommand(sql, conn);
  SqlDataAdapter adapter = new SqlDataAdapter(SqlCmd);
  DataSet ds = new DataSet();
  conn.Open();
  adapter.Fill(ds);
  conn.Close();

  DataTable tDt = ds.Tables[0];



  viewer.LocalReport.DataSources.Clear();
  viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DataSet1", tDt));
  viewer.LocalReport.Refresh();


  //呼叫ReportViewer.LoadReport的Render function,將資料轉成想要轉換的格式,並產生成Byte資料
  byte[] tBytes = viewer.LocalReport.Render(pType, null, out tMimeType, out tEncoding, out tExtension, out tStreamids, out tWarnings);

  //將Byte內容寫到Client

  using (FileStream fs = new FileStream(@"D:\ProjTest\MyTest.pdf", FileMode.Create))
  {
   fs.Write(tBytes, 0, tBytes.Length);
   fs.Close();
  }


 } 
}


這樣,就能夠產生報表了(位於 D:\ProjTest\MyTest.pdf)。

在測試過程中,曾經發生「報表定義具有無效的目標命名空間 'http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition'」這錯誤,經過「RDLC命名空间引用错误的解决方法」的介紹,發現是自己所參考的Microsoft.ReportViewer.WebForms 版本錯誤所致,所以在引用參考時,要選對版本。

後記:

以上測試程式的環境為 .Net FrameWork 3.5,我在 .Net FrameWork 2.0 發現找不到參考 「Microsoft.ReportViewer.WebForms」,但卻有 「Microsoft.ReportViewer.WinForms」。於是我改成參考 「Microsoft.ReportViewer.WinForms」,也可以成功。

只是要多參考一個:「System.Windows.Forms」

而 progarm.cs 有兩處要修改:

1. Microsoft.Reporting.WebForms.Warning[] tWarnings;
   改成
   Microsoft.Reporting.WinForms.Warning[] tWarnings;

2.viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DataSet1", tDt));
   改成
viewer.LocalReport.DataSources.Add(new Microsoft.Reporting.WinForms.ReportDataSource("DataSet1", tDt));

補充:
01:如果有需要合併多張報表,可參考「LocalReport 報表合併後變成空白」。




參考:
01:[C#]透過ReportViewer將報表另存成檔案
02:如何製作LocalReport-進階版(下)
03:如何製作LocalReport-簡易版(上)
04:Rendering RDLC to pdf output console application
05:RDLC命名空间引用错误的解决方法

2016年3月18日 星期五

Creating Control Error

真的是很意外,VS 2010 一開起來,程式可以編譯,但 Design 畫面全部都出現錯誤。

出現了 「creating control Error HRESULT E_FAIL has been returned from a call to a COM component」,網路上能夠出現這種錯誤的人似乎有,但不多。但有看到一篇「Error HRESULT E_FAIL has been returned from a call to a COM component」似乎在講很類似的問題。

主要是 ProjectTemplatesCache 出現問題,建議刪除後,再重建。

於是抱持著實驗精神,在「C:\Program Files(x86)\Microsoft Visual Studio 10.0\Common7\IDE\ProjectTemplatesCache」找到了如下的檔案:


於是我關閉所有  Visual Studio 2010 視窗,並將 ProjectTemplatesCache 整個資料夾刪除,然後再透過 cmd.exe 進到

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE>

並執行  devenv  /setup

然後重新開啟 Visual Studio 2010,所有 Design 介面的控制項就可以恢復正常了。