<?xml version="1.0" encoding="UTF-8" standalone="no"?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:gd="http://schemas.google.com/g/2005" xmlns:georss="http://www.georss.org/georss" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:thr="http://purl.org/syndication/thread/1.0"><id>tag:blogger.com,1999:blog-2573692172331948535</id><updated>2024-09-14T19:30:00.117+08:00</updated><category term="ASP.NET"/><category term="JavaScript"/><category term="C#"/><category term="T-SQL"/><category term=".NET"/><category term="AJAX"/><category term="ADO.NET"/><category term="Security"/><category term="Best Practices"/><category term="Crystal Reports"/><category term="Entity Framework"/><category term="IE"/><category term="MooTools"/><category term="SQL Server"/><category term="iTextSharp"/><category term="jQuery"/><category term="Blogger Hack"/><category term="CKIP"/><category term="CSS"/><category term="Chrome"/><category term="DevExpress"/><category term="E-Commerce"/><category term="LINQ"/><category term="NDde"/><category term="P3P"/><category term="Plugin"/><category term="Regular Expression"/><category term="User Control"/><title type="text">renjin's blog</title><subtitle type="html">關於程式設計的學習筆記</subtitle><link href="http://renjin.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default?redirect=false" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/" rel="alternate" type="text/html"/><link href="http://pubsubhubbub.appspot.com/" rel="hub"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default?start-index=26&amp;max-results=25&amp;redirect=false" rel="next" type="application/atom+xml"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><generator uri="http://www.blogger.com" version="7.00">Blogger</generator><openSearch:totalResults>49</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-6460560332192112780</id><published>2011-01-16T16:32:00.034+08:00</published><updated>2011-01-23T23:16:10.256+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><title type="text">為 Windows Form 自動設定等待游標</title><content type="html">在 Windows Form 應用程式中，我們通常會透過變換不同的滑鼠游標形狀（例如沙漏形狀的等待游標），來回應需要使用者等待處理完成的請求，直到處理完成再將游標恢復為預設狀態為止。&lt;br /&gt;&lt;br /&gt;為達此目地，一般會在可能需要等待處理的程序中，先將表單的 Cursor 屬性設為 Cursors.WaitCursor，並在作業完成時再將其設為 Cursors.DefaultCursor。同時，為了避免因執行階段的異常情況（Exception）而導致游標狀態異常，會將重設游標的程式碼置於例外處理陳述式的 Finally 區塊中，以確保游標會回復成正常狀態。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;雖然，控制游標的作法很簡單，但撰寫仍略嫌瑣碎，如果透過自訂實作 &lt;a href="http://msdn.microsoft.com/zh-tw/library/system.idisposable.aspx"&gt;IDisposable 介面&lt;/a&gt;的類別，來封裝變更、重設游標的細節，便可讓程式碼更為簡潔，如以下範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;using(new WaitCursor()) {&lt;br /&gt;   //... some long-running code here&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;採用此實作方式，或許會讓你覺得事情已經簡單到不能再簡單了，但事實上，&lt;a href="http://www.vbusers.com/codecsharp/codeget.asp?ThreadID=58"&gt;AutoWaitCursor 類別&lt;/a&gt;提供了更佳的實現方法。它會自動偵測表單應用程式是否處於忙碌狀態（停止回應），若忙碌逾指定的 Delay 時間（預設為 25 毫秒），則會自動顯示忙碌游標（預設為等待游標），直到應用程式恢復閒置後重設狀態。你只需在表單建構式中，加入少量的程式碼，便可以為你表單應用程式自動設置等待游標的功能，如以下範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;AutoWaitCursor.MainWindowHandle = this.Handle;&lt;br /&gt;AutoWaitCursor.Start();&lt;/pre&gt;&lt;br /&gt;值得注意的是，如果你的表單應用程式使用多執行緒，除非表單的主執行緒被封鎖，否則游標將不會自動改變。&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.vbusers.com/codecsharp/codeget.asp?ThreadID=58"&gt;Automatically setting the wait cursor for an application&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/6460560332192112780/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2011/01/automatically-setting-wait-cursor.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6460560332192112780" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6460560332192112780" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2011/01/automatically-setting-wait-cursor.html" rel="alternate" title="為 Windows Form 自動設定等待游標" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-5677671591544235695</id><published>2010-10-29T20:35:00.027+08:00</published><updated>2011-06-04T21:40:01.870+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="iTextSharp"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><title type="text">Printing PDF File from ASP.NET</title><content type="html">使用 PDF（Portable Document Format）文件格式的好處在於，不論使用何種電腦平台或作業系統，都能忠實重現文件的原貌，也不會因為印表機的不同而影響排版。因此，PDF 格式在不同設備上輸出列印的一致性，非常適合用在印表機列印輸出的需求。&lt;br /&gt;&lt;br /&gt;在網頁設計實務上，需要動態產生文件及講求排版格式的列印功能亦頗為常見。本文將示範如何使用 &lt;a href="http://sourceforge.net/projects/itextsharp/"&gt;iTextShap&lt;/a&gt; 建立 PDF 文件，並加入 JavaScript 指令碼透過 &lt;a href="http://www.adobe.com/devnet/acrobat/javascript.html"&gt;Acrobat API&lt;/a&gt; 將文件自動輸出至指定的印表機。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;下列程式碼範例會假設已經在 ASP.NET Web 網頁建立列印按鈕，並指定如下的 Click 事件處理常式。範例中的 PrintButton_Click 方法，會在指定的目錄下將建立含有列印指令碼的 PDF 文件，並透過泛型處理常式將文件傳送到用戶端，然後輸出至使用者的印表機。&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;protected void PrintButton_Click(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;    Document document = new Document();                &lt;br /&gt;    MemoryStream ms = new MemoryStream();&lt;br /&gt;    PdfWriter writer = PdfWriter.GetInstance(document, ms);&lt;br /&gt;    document.Open();&lt;br /&gt;&lt;br /&gt;    // 加入自動列印指令碼&lt;br /&gt;    writer.AddJavaScript(@"&lt;br /&gt;    var pp = this.getPrintParams();&lt;br /&gt;    pp.interactive = pp.constants.interactionLevel.silent;        &lt;br /&gt;    pp.pageHandling = pp.constants.handling.none;&lt;br /&gt;    var fv = pp.constants.flagValues;&lt;br /&gt;    pp.flags |= fv.setPageSize;&lt;br /&gt;    pp.flags |= (fv.suppressCenter | fv.suppressRotate);&lt;br /&gt;    this.print(pp);&lt;br /&gt;    ");&lt;br /&gt;&lt;br /&gt;    document.Add(new Paragraph("Testing Silent Printing with iTextSharp."));&lt;br /&gt;    document.Close();&lt;br /&gt;&lt;br /&gt;    Response.ClearContent();&lt;br /&gt;    Response.ClearHeaders();&lt;br /&gt;    Response.ContentType = "application/pdf";&lt;br /&gt;    Response.AddHeader("Content-Disposition", "inline; filename=Report.pdf");&lt;br /&gt;    Response.BinaryWrite(ms.ToArray());&lt;br /&gt;    Response.End();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.sanjbee.com/content/?p=96"&gt;Silent Printing on Web based Java Application&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/5677671591544235695/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/10/printing-pdf-file-from-aspnet.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5677671591544235695" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5677671591544235695" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/10/printing-pdf-file-from-aspnet.html" rel="alternate" title="Printing PDF File from ASP.NET" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-252001227578938284</id><published>2010-09-26T12:03:00.017+08:00</published><updated>2010-10-31T13:03:05.849+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="DevExpress"/><title type="text">Returning Value from ASPxPopupControl</title><content type="html">ASPxPopupControl 是 Developer Express 在 &lt;a href="http://www.devexpress.com/Products/NET/Controls/ASP/ASPxperience/index.xml"&gt;ASPxperience Suite&lt;/a&gt; 裡面所提供的 Web 控制項。你不僅可以利用它填入 HTML 內容外，也可以指定特定的網頁來為你的網頁加入快顯視窗功能。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;當你使用 ASPxPopupControl 的 ContentUrl 屬性設定開啟網頁時，它會建立內嵌框架載入網頁內容。為了利於在內嵌網頁中傳遞值給主網頁及隱藏快顯視窗所需的物件參考，需在其 init 事件加入必要的初始化程式碼。&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;&amp;lt;%@ Page Language="C#" AutoEventWireup="true" %&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Returning Value from ASPxPopupControl&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="form1" runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;div&amp;gt;        &lt;br /&gt;        &amp;lt;table border="0"&amp;gt;&lt;br /&gt;            &amp;lt;tr&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&lt;br /&gt;                    &amp;lt;dx:ASPxTextBox ID="supplierTextBox" runat="server" &lt;br /&gt;                    ClientInstanceName="supplierTextBox" Width="80" /&amp;gt;&lt;br /&gt;                &amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&lt;br /&gt;                    &amp;lt;dx:ASPxButton ID="popupButton" runat="server" Text="..." /&amp;gt;&lt;br /&gt;                &amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;/table&amp;gt;&lt;br /&gt;        &amp;lt;dx:ASPxPopupControl ID="suppliersPopup" runat="server" &lt;br /&gt;            ClientInstanceName="suppliersPopup" AllowDragging="True" &lt;br /&gt;            AllowResize="True" CloseAction="CloseButton" &lt;br /&gt;            ContentUrl="SlavePage.aspx" Width="400" Height="450" &lt;br /&gt;            ContentStyle-Paddings-Padding="2" HeaderText="Select Supplier"&lt;br /&gt;            PopupElementID="popupButton"&amp;gt;&lt;br /&gt;            &amp;lt;ClientSideEvents Init="function(s, e) {&lt;br /&gt;                    var iframe = s.GetContentIFrame();&lt;br /&gt;                    iframe.contentLoaded = false;&lt;br /&gt;                    var controlCollection = ASPxClientControl.GetControlCollection(); &lt;br /&gt;                    iframe.popupArguments = {&lt;br /&gt;                        popupContainer: controlCollection.Get('suppliersPopup'),&lt;br /&gt;                        controlToAssign: controlCollection.Get('supplierTextBox')&lt;br /&gt;                    };&lt;br /&gt;            }"&amp;gt;&amp;lt;/ClientSideEvents&amp;gt;&lt;br /&gt;        &amp;lt;/dx:ASPxPopupControl&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;以下程式碼示範如何在內嵌框架頁面中傳值給主網頁並隱藏快顯視窗：&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;&amp;lt;%@ Page Language="C#" AutoEventWireup="true" %&amp;gt;&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Select Supplier&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;        function getOuterFrame() {&lt;br /&gt;            var iframes = window.parent.document.getElementsByTagName("iframe");&lt;br /&gt;            for (var i = 0, len = iframes.length; i &amp;lt; len; i++) {&lt;br /&gt;                var doc = iframes[i].contentDocument || iframes[i].contentWindow.document;&lt;br /&gt;                if (doc === document) {&lt;br /&gt;                    return iframes[i];&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            return null;&lt;br /&gt;        }&lt;br /&gt;        function hidePopupWindow() {&lt;br /&gt;            var outerFrame = getOuterFrame();&lt;br /&gt;            if (outerFrame !== null) {&lt;br /&gt;                outerFrame.popupArguments.popupContainer.Hide();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        function setReturnValue(v) {&lt;br /&gt;            var outerFrame = getOuterFrame();&lt;br /&gt;            if (outerFrame !== null) {&lt;br /&gt;                var controlToAssign = outerFrame.popupArguments.controlToAssign;&lt;br /&gt;                if (controlToAssign) {&lt;br /&gt;                    controlToAssign.SetText(v);&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            hidePopupWindow();&lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script runat="server"&amp;gt;&lt;br /&gt;        void OkButton_Click(object sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            if (grid.FocusedRowIndex &amp;gt; -1)&lt;br /&gt;            {&lt;br /&gt;                object key = grid.GetRowValues(grid.FocusedRowIndex, grid.KeyFieldName);&lt;br /&gt;                Page.ClientScript.RegisterClientScriptBlock(this.GetType(),&lt;br /&gt;                    "SetReturnValue", "setReturnValue('" + key.ToString() + @"');&lt;br /&gt;                ", true);&lt;br /&gt;            }&lt;br /&gt;        }       &lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="form1" runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;div&amp;gt;&lt;br /&gt;        &amp;lt;dx:ASPxGridView ID="grid" runat="server" &lt;br /&gt;            ClientInstanceName="grid" DataSourceID="NorthwindDataSource"&lt;br /&gt;            KeyFieldName="SupplierID" AutoGenerateColumns="false" Width="100%"&amp;gt;&lt;br /&gt;            &amp;lt;Columns&amp;gt;&lt;br /&gt;                &amp;lt;dx:GridViewDataCheckColumn&amp;gt;&lt;br /&gt;                    &amp;lt;DataItemTemplate&amp;gt;&lt;br /&gt;                        &amp;lt;input type="radio" name="radioButton" /&amp;gt;&lt;br /&gt;                    &amp;lt;/DataItemTemplate&amp;gt;&lt;br /&gt;                &amp;lt;/dx:GridViewDataCheckColumn&amp;gt;&lt;br /&gt;                &amp;lt;dx:GridViewDataColumn FieldName="CompanyName" Caption="Company Name" /&amp;gt;&lt;br /&gt;                &amp;lt;dx:GridViewDataColumn FieldName="ContactName" Caption="Contact Name" /&amp;gt;&lt;br /&gt;            &amp;lt;/Columns&amp;gt;&lt;br /&gt;            &amp;lt;SettingsBehavior AllowFocusedRow="True" /&amp;gt;&lt;br /&gt;            &amp;lt;ClientSideEvents FocusedRowChanged="function(s, e) {&lt;br /&gt;               var row = s.GetRow(s.GetFocusedRowIndex());&lt;br /&gt;                if(__aspxIE)&lt;br /&gt;                    row.cells[0].childNodes[0].checked = true;&lt;br /&gt;                else&lt;br /&gt;                    row.cells[0].childNodes[1].checked = true;&lt;br /&gt;            }" /&amp;gt;&lt;br /&gt;        &amp;lt;/dx:ASPxGridView&amp;gt;&lt;br /&gt;        &amp;lt;br /&amp;gt;&lt;br /&gt;        &amp;lt;table border="0" align="center"&amp;gt;&lt;br /&gt;            &amp;lt;tr&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&lt;br /&gt;                    &amp;lt;dx:ASPxButton ID="OkButton" runat="server" Text="OK" &lt;br /&gt;                           OnClick="OkButton_Click" /&amp;gt;&lt;br /&gt;                &amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&lt;br /&gt;                    &amp;lt;dx:ASPxButton ID="CancelButton" runat="server" Text="Cancel"&amp;gt;&lt;br /&gt;                        &amp;lt;ClientSideEvents Click="function(s, e) {&lt;br /&gt;                        hidePopupWindow();&lt;br /&gt;                        }" /&amp;gt;&lt;br /&gt;                    &amp;lt;/dx:ASPxButton&amp;gt;&lt;br /&gt;                &amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;/tr&amp;gt;&lt;br /&gt;        &amp;lt;/table&amp;gt;&lt;br /&gt;        &amp;lt;asp:AccessDataSource ID="NorthwindDataSource" runat="server" &lt;br /&gt;            DataFile="~/App_Data/Northwind.mdb"&lt;br /&gt;            SelectCommand="SELECT * FROM Suppliers"&amp;gt;&amp;lt;/asp:AccessDataSource&amp;gt;        &lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.office.live.com/self.aspx/Source/dxSample.zip"&gt;Download sample code&lt;/a&gt;&lt;/nobr&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/252001227578938284/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/09/returning-value-from-aspxpopupcontrol.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/252001227578938284" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/252001227578938284" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/09/returning-value-from-aspxpopupcontrol.html" rel="alternate" title="Returning Value from ASPxPopupControl" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s72-c/download.gif" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-5183332999553896929</id><published>2010-07-23T15:34:00.014+08:00</published><updated>2010-07-26T11:09:40.119+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ADO.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><title type="text">SQL Server 連線共用的問題</title><content type="html">在預設的情況下，SQL Server 的 .NET Framework 資料提供者會自動提供連線共用（Connection Pooling），以利提升應用程式的延展性及效能。然而，當 ADO.NET 用戶端嘗試使用共用連線時，有可能會遇到如下的例外狀況：&lt;br /&gt;&lt;blockquote&gt;在傳送要求至伺服器時發生傳輸層級的錯誤。 (provider: TCP 提供者, error: 0 - 遠端主機已強制關閉一個現存的連線。)&lt;br /&gt;&lt;br /&gt;A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An existing connection was forcibly closed by the remote host.)&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;如果共用連線集區的可用連線與伺服器的連接已嚴重損毀，例如：伺服器重新啟動、容錯移轉、使用者處理序被刪除等，連線共用器並無法立即發現異常，直到將其傳回至 ADO.NET 呼叫端並嘗試與伺服器進行通訊後，才會偵測到連接已損毀。當發生此情況時，連線共用器會從集區中移除該連線，並且擲回如上的例外狀況。&lt;br /&gt;&lt;br /&gt;連線共用機制並非能完全保證可用連線的有效性，除非你在連線字串中指定 Pooling=false 明確停用，否則你難以避免此類問題發生。除此之外，建議你在資料存取程式碼中加入例外處理常式因應，或是使用 &lt;a href="http://www.diranieh.com/DataAccessPatterns/ResouceRetryer.htm"&gt;Retryer Pattern&lt;/a&gt; 做最佳的容錯處理。&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/zh-tw/library/8xx3tyca.aspx"&gt;SQL Server 連接共用 (ADO.NET)&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/5183332999553896929/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/07/sql-server-connection-pooling-problem.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5183332999553896929" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5183332999553896929" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/07/sql-server-connection-pooling-problem.html" rel="alternate" title="SQL Server 連線共用的問題" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-5688044805468673819</id><published>2010-07-03T22:59:00.043+08:00</published><updated>2010-07-06T09:21:55.016+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="User Control"/><title type="text">ASP.NET DateDropDown Control</title><content type="html">DateDropDown 是一個使用 UpdatePanel 控制項所建立的連動下拉式日期使用者控制項（User Control）。你可以設定 MinDate 和 MaxDate 屬性，來限制使用者能夠選取的日期範圍，同時也可以搭配驗證控制項檢查使用者輸入的值。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;DateDropDown 控制項的完整程式碼如下：&lt;br /&gt;&lt;span class="source-code-title"&gt;DateDropDown.ascx&lt;/span&gt;&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;&amp;lt;%@ Control Language="C#" AutoEventWireup="true" CodeFile="DateDropDown.ascx.cs" &lt;br /&gt;Inherits="DateDropDown" %&amp;gt;&lt;br /&gt;&amp;lt;asp:UpdatePanel ID="uxUpdatePanel" runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;ContentTemplate&amp;gt;&lt;br /&gt;        &amp;lt;table cellpadding="0" cellspacing="0" border="0"&amp;gt;&lt;br /&gt;            &amp;lt;tr&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;asp:DropDownList id="uxYearList" runat="server" AutoPostBack="true" &lt;br /&gt;                OnSelectedIndexChanged="uxYearList_SelectedIndexChanged"&amp;gt;&lt;br /&gt;                &amp;lt;/asp:DropDownList&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;年&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;asp:DropDownList id="uxMonthList" runat="server" AutoPostBack="true" &lt;br /&gt;                OnSelectedIndexChanged="uxMonthList_SelectedIndexChanged"&amp;gt;&lt;br /&gt;                    &amp;lt;asp:ListItem Text="請選擇"&amp;gt;&amp;lt;/asp:ListItem&amp;gt;&lt;br /&gt;                &amp;lt;/asp:DropDownList&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;月&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;&amp;lt;asp:DropDownList id="uxDayList" runat="server"&amp;gt;&lt;br /&gt;                    &amp;lt;asp:ListItem Text="請選擇"&amp;gt;&amp;lt;/asp:ListItem&amp;gt;&lt;br /&gt;                &amp;lt;/asp:DropDownList&amp;gt;&amp;lt;/td&amp;gt;&lt;br /&gt;                &amp;lt;td&amp;gt;日&amp;lt;/td&amp;gt;&lt;br /&gt;            &amp;lt;/tr&amp;gt;    &lt;br /&gt;        &amp;lt;/table&amp;gt;    &lt;br /&gt;    &amp;lt;/ContentTemplate&amp;gt;&lt;br /&gt;&amp;lt;/asp:UpdatePanel&amp;gt;&lt;br /&gt;&amp;lt;script language="javascript" type="text/javascript"&amp;gt;&lt;br /&gt;Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(&lt;br /&gt;function(sender, e) {&lt;br /&gt;    var elem = e.get_postBackElement();&lt;br /&gt;    if (elem.id == '&amp;lt;%= uxYearList.ClientID %&amp;gt;') {&lt;br /&gt;        $get('&amp;lt;%= uxMonthList.ClientID %&amp;gt;').disabled = true;&lt;br /&gt;        $get('&amp;lt;%= uxDayList.ClientID %&amp;gt;').disabled = true;&lt;br /&gt;        $get('&amp;lt;%= this.ClientID %&amp;gt;').value = '';&lt;br /&gt;    }&lt;br /&gt;    else if (elem.id == '&amp;lt;%= uxMonthList.ClientID %&amp;gt;') {&lt;br /&gt;        $get('&amp;lt;%= uxDayList.ClientID %&amp;gt;').disabled = true;&lt;br /&gt;        $get('&amp;lt;%= this.ClientID %&amp;gt;').value = '';&lt;br /&gt;    }     &lt;br /&gt;});&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;span class="source-code-title"&gt;DateDropDown.ascx.cs&lt;/span&gt;&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;using System;&lt;br /&gt;using System.Reflection;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.UI;&lt;br /&gt;using System.Web.UI.WebControls;&lt;br /&gt;&lt;br /&gt;/// &amp;lt;summary&amp;gt;&lt;br /&gt;/// 連動下拉式日期控制項&lt;br /&gt;/// &amp;lt;/summary&amp;gt;&lt;br /&gt;[ValidationProperty("Text")]&lt;br /&gt;public partial class DateDropDown : System.Web.UI.UserControl&lt;br /&gt;{        &lt;br /&gt;    readonly int _maxYear = DateTime.Today.Year + 20;&lt;br /&gt;    readonly int _minYear = DateTime.Today.Year - 20;&lt;br /&gt;    const string _promptText = "請選擇";&lt;br /&gt;&lt;br /&gt;    protected void Page_Load(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        if (!Page.IsPostBack)&lt;br /&gt;        {&lt;br /&gt;            Initialize();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        ScriptManager.RegisterHiddenField(uxUpdatePanel, this.ClientID, this.Text);&lt;br /&gt;        RegisterScript();        &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void Initialize()&lt;br /&gt;    {&lt;br /&gt;        if (Initialized)&lt;br /&gt;            return;&lt;br /&gt;&lt;br /&gt;        Initialized = true;&lt;br /&gt;        PopulateYearList();&lt;br /&gt;        AssignValidation();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void RegisterScript()&lt;br /&gt;    {&lt;br /&gt;        string script = string.Format(&lt;br /&gt;            @"$get('{0}').onchange = function() {{&lt;br /&gt;                $get('{1}').value = &lt;br /&gt;                    ($get('{2}').selectedIndex &gt; 0 &amp;&amp; $get('{3}').selectedIndex &gt; 0 &lt;br /&gt;                    &amp;&amp; this.selectedIndex &gt; 0) ?&lt;br /&gt;                    $get('{2}').value + '-' + $get('{3}').value + '-' + this.value : '';&lt;br /&gt;            }};&lt;br /&gt;            ", uxDayList.ClientID, ClientID, uxYearList.ClientID, uxMonthList.ClientID);&lt;br /&gt;&lt;br /&gt;        ScriptManager.RegisterStartupScript(Page, Page.GetType(), UniqueID + "_onchange",&lt;br /&gt;            script, true);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private bool Initialized&lt;br /&gt;    {&lt;br /&gt;        set &lt;br /&gt;        {&lt;br /&gt;            ViewState["Initialized"] = value;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            if (ViewState["Initialized"] == null)&lt;br /&gt;                ViewState["Initialized"] = false;&lt;br /&gt;            &lt;br /&gt;            return (bool)ViewState["Initialized"];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;   &lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// 取得選取的日期字串&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public string Text&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            if (uxYearList.SelectedIndex == 0 || uxMonthList.SelectedIndex == 0 &lt;br /&gt;                || uxDayList.SelectedIndex == 0)&lt;br /&gt;                return string.Empty;&lt;br /&gt;&lt;br /&gt;            return new DateTime(int.Parse(uxYearList.SelectedValue), &lt;br /&gt;                int.Parse(uxMonthList.SelectedValue), &lt;br /&gt;                int.Parse(uxDayList.SelectedValue)).ToString("yyyy-MM-dd");&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// 取得或設定驗證群組名稱&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public string ValidationGroup&lt;br /&gt;    {&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            return (string)ViewState["ValidationGroup"];&lt;br /&gt;        }&lt;br /&gt;        set&lt;br /&gt;        {&lt;br /&gt;            ViewState["ValidationGroup"] = value;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// 最小日期值&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public DateTime MinDate&lt;br /&gt;    {&lt;br /&gt;        set&lt;br /&gt;        {&lt;br /&gt;            ViewState["MinDate"] = value;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            if (ViewState["MinDate"] == null)            &lt;br /&gt;                ViewState["MinDate"] = new DateTime(_minYear, 1, 1);&lt;br /&gt;            &lt;br /&gt;            return (DateTime)ViewState["MinDate"];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// 最大日期值&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public DateTime MaxDate&lt;br /&gt;    {&lt;br /&gt;        set&lt;br /&gt;        {&lt;br /&gt;            ViewState["MaxDate"] = value;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            if (ViewState["MaxDate"] == null)&lt;br /&gt;                ViewState["MaxDate"] = new DateTime(_maxYear, 12, 31);&lt;br /&gt;            &lt;br /&gt;            return (DateTime)ViewState["MaxDate"];&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    /// &amp;lt;summary&amp;gt;&lt;br /&gt;    /// 取得或設定選取的日期&lt;br /&gt;    /// &amp;lt;/summary&amp;gt;&lt;br /&gt;    public DateTime SelectedDate&lt;br /&gt;    {&lt;br /&gt;        set&lt;br /&gt;        {            &lt;br /&gt;            if (value &amp;lt; MinDate || value &amp;gt; MaxDate)&lt;br /&gt;                throw new ArgumentOutOfRangeException("SelectedDate",&lt;br /&gt;                    "The value should be between 'MinDate' and 'MaxDate'.");&lt;br /&gt;&lt;br /&gt;            Initialize();&lt;br /&gt;            uxYearList.SelectedValue = value.Year.ToString();&lt;br /&gt;            (uxYearList as IPostBackDataHandler).RaisePostDataChangedEvent();&lt;br /&gt;            uxMonthList.SelectedValue = value.Month.ToString();&lt;br /&gt;            (uxMonthList as IPostBackDataHandler).RaisePostDataChangedEvent();&lt;br /&gt;            uxDayList.SelectedValue = value.Day.ToString();&lt;br /&gt;            ScriptManager.RegisterExpandoAttribute(uxUpdatePanel,&lt;br /&gt;                ClientID, "value", Text, false);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        get&lt;br /&gt;        {&lt;br /&gt;            Initialize();&lt;br /&gt;&lt;br /&gt;            DateTime selectedValue;&lt;br /&gt;            if (DateTime.TryParse(Text, out selectedValue))&lt;br /&gt;                return selectedValue;&lt;br /&gt;                            &lt;br /&gt;            return DateTime.MinValue;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected void AssignValidation()&lt;br /&gt;    {&lt;br /&gt;        foreach (Control control in this.Controls)&lt;br /&gt;        {&lt;br /&gt;            PropertyInfo property = control.GetType().GetProperty("ValidationGroup");&lt;br /&gt;            if (property != null)&lt;br /&gt;            {&lt;br /&gt;                property.SetValue(control, ValidationGroup, null);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void PopulateYearList()&lt;br /&gt;    {        &lt;br /&gt;        uxYearList.Items.Clear();&lt;br /&gt;        uxYearList.Items.Add(new ListItem(_promptText));&lt;br /&gt;&lt;br /&gt;        for (int y = MinDate.Year; y &amp;lt;= MaxDate.Year; y++)&lt;br /&gt;        {&lt;br /&gt;            uxYearList.Items.Add(new ListItem(y.ToString(), y.ToString()));&lt;br /&gt;            if (SelectedDate != DateTime.MinValue &amp;&amp; y == SelectedDate.Year)&lt;br /&gt;            {&lt;br /&gt;                uxYearList.Items.FindByValue(y.ToString()).Selected = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void PopulateMonthList(int year)&lt;br /&gt;    {&lt;br /&gt;        uxMonthList.Items.Clear();&lt;br /&gt;        uxMonthList.Items.Add(new ListItem(_promptText));&lt;br /&gt;&lt;br /&gt;        int minMonth = MinDate.Year == year ? MinDate.Month : 1;&lt;br /&gt;        int maxMonth = MaxDate.Year == year ? MaxDate.Month : 12;&lt;br /&gt;&lt;br /&gt;        for (int m = minMonth; m &amp;lt;= maxMonth; m++)&lt;br /&gt;        {&lt;br /&gt;            uxMonthList.Items.Add(new ListItem(m.ToString(), m.ToString()));&lt;br /&gt;            if (SelectedDate != DateTime.MinValue &amp;&amp; m == SelectedDate.Month)&lt;br /&gt;            {&lt;br /&gt;                uxMonthList.Items.FindByValue(m.ToString()).Selected = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        uxMonthList.Enabled = true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void PopulateDayList(int year, int month)&lt;br /&gt;    {        &lt;br /&gt;        uxDayList.Items.Clear();&lt;br /&gt;        uxDayList.Items.Add(new ListItem(_promptText));&lt;br /&gt;        &lt;br /&gt;        int minDay = MinDate.Year == year &amp;&amp; MinDate.Month == month ? MinDate.Day : 1;&lt;br /&gt;        int maxDay = MaxDate.Year == year &amp;&amp; MaxDate.Month == month ? &lt;br /&gt;            MaxDate.Day : DateTime.DaysInMonth(year, month);&lt;br /&gt;&lt;br /&gt;        for (int d = minDay; d &amp;lt;= maxDay; d++)&lt;br /&gt;        {&lt;br /&gt;            uxDayList.Items.Add(new ListItem(d.ToString(), d.ToString()));&lt;br /&gt;            if (SelectedDate != DateTime.MinValue &amp;&amp; d == SelectedDate.Day)&lt;br /&gt;            {&lt;br /&gt;                uxDayList.Items.FindByValue(d.ToString()).Selected = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        uxDayList.Enabled = true;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected void uxYearList_SelectedIndexChanged(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        if (uxYearList.SelectedIndex == 0)&lt;br /&gt;        {&lt;br /&gt;            uxMonthList.SelectedIndex = uxDayList.SelectedIndex = 0;&lt;br /&gt;            uxMonthList.Enabled = uxDayList.Enabled = false;&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        PopulateMonthList(int.Parse(uxYearList.SelectedValue));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected void uxMonthList_SelectedIndexChanged(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        if (uxMonthList.SelectedIndex == 0)&lt;br /&gt;        {&lt;br /&gt;            uxDayList.SelectedIndex = 0;&lt;br /&gt;            uxDayList.Enabled = false;&lt;br /&gt;            return;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        PopulateDayList(int.Parse(uxYearList.SelectedValue), &lt;br /&gt;            int.Parse(uxMonthList.SelectedValue));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;下列程式碼範例要求使用者輸入一個介於 2009-07-01 到 2010-07-01 之間的日期，並使用 RequiredFieldValidator 來確認控制項的輸入。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;uc1:DateDropDown ID="DateDropDown1" runat="server" ValidationGroup="DateDropDown" &lt;br /&gt;MinDate="2009-07-01" MaxDate="2010-07-01" /&amp;gt;&lt;br /&gt;&amp;lt;asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" &lt;br /&gt;ControlToValidate="DateDropDown1" ValidationGroup="DateDropDown" &lt;br /&gt;ErrorMessage="Please enter a Date!"&amp;gt;&amp;lt;/asp:RequiredFieldValidator&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.office.live.com/self.aspx/Source/DateDropDown.zip"&gt;Download DateDropDown.zip&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/5688044805468673819/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/07/aspnet-datedropdown-control.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5688044805468673819" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5688044805468673819" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2010/07/aspnet-datedropdown-control.html" rel="alternate" title="ASP.NET DateDropDown Control" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s72-c/download.gif" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-8406980937670531741</id><published>2009-11-03T15:53:00.006+08:00</published><updated>2009-11-03T15:54:56.800+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework"/><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server"/><title type="text">Problem Using INSTEAD OF Triggers with Entity Framework</title><content type="html">若你在使用識別資料行做為主索引鍵的資料表中，定義 INSTEAD OF INSERT 觸發程序，並透過 ObjectContext 的 &lt;a href="http://msdn.microsoft.com/zh-tw/library/bb336792.aspx"&gt;SaveChanges&lt;/a&gt; 方法新增資料時，將會引發 OptimisticConcurrencyException，並導致整個交易復原。以下是發生例外狀況的錯誤訊息：&lt;br /&gt;&lt;blockquote&gt;存放區更新、插入或刪除陳述式影響到非預期數目的資料列 (0)。這些實體載入之後可能被修改或刪除了。請重新整理 ObjectStateManager 實體。&lt;br /&gt;&lt;br /&gt;Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;如以下範例，會依據 AdventureWorks 實體資料模型的定義，將新的實體物件附加到物件內容：&lt;br /&gt;&lt;pre&gt;using (AdventureWorksEntities context = new AdventureWorksEntities()) &lt;br /&gt;{&lt;br /&gt;    context.AddToSalesReason(new SalesReason() {&lt;br /&gt;        Name = "Recommendation", ReasonType = "Other", ModifiedDate = DateTime.Now&lt;br /&gt;    });&lt;br /&gt;    context.SaveChanges();&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;當呼叫 SaveChanges 方法時，物件服務會產生及執行以下 SQL 命令：&lt;br /&gt;&lt;pre&gt;exec sp_executesql N'insert [Sales].[SalesReason]([Name], [ReasonType], [ModifiedDate])&lt;br /&gt;values (@0, @1, @2)&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;select [SalesReasonID]&lt;br /&gt;from [Sales].[SalesReason]&lt;br /&gt;where @@ROWCOUNT &amp;gt; 0 and [SalesReasonID] = scope_identity()&lt;/span&gt;'&lt;br /&gt;,N'@0 nvarchar(14),@1 nvarchar(5),@2 datetime2(7)'&lt;br /&gt;,@0=N'Recommendation',@1=N'Other',@2='2009-11-02 15:14:54.4856524'&lt;/pre&gt;&lt;br /&gt;因為該實體物件包含識別插入的實體索引鍵，所以會在 INSERT 陳述式後，搭配使用 &lt;a href="http://msdn.microsoft.com/zh-tw/library/ms190315(SQL.90).aspx"&gt;SCOPE_IDENTITY&lt;/a&gt; 函數以取得插入識別欄位中的最後一個識別值。然而，如果此資料表已定義 INSTEAD OF INSERT 觸發程序，則 SCOPE_IDENTITY 函數會因為分屬不同的範圍（Scope）而傳回 NULL 值，於是導致 SaveChanges 失敗，而復原該筆交易並擲回如前述的 OptimisticConcurrencyException 例外狀況。&lt;br /&gt;&lt;br /&gt;要解決這個問題，你可以使用預儲程序取代 INSTEAD OF INSERT 觸發程序，然後利用實體資料模型設計工具（Entity Designer），&lt;a href="http://msdn.microsoft.com/zh-tw/library/cc716711.aspx"&gt;把實體類型的修改函式對應至預存程序&lt;/a&gt;。或者，你也可以使用 &lt;a href="http://blogs.msdn.com/adonet/archive/2008/12/02/migrating-from-linq-to-sql-to-the-entity-framework-stored-procedures-for-data-retrieval.aspx"&gt;ExecuteCommand&lt;/a&gt; 擴充方法來直接執行新增作業的預儲程序。&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/8406980937670531741/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/11/problem-using-instead-of-triggers.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8406980937670531741" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8406980937670531741" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/11/problem-using-instead-of-triggers.html" rel="alternate" title="Problem Using INSTEAD OF Triggers with Entity Framework" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-1506901775740741654</id><published>2009-10-14T14:42:00.034+08:00</published><updated>2009-11-03T15:36:34.698+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Entity Framework"/><title type="text">How to Fix "Unable to update the EntitySet" Error</title><content type="html">如果你嘗試對資料表實體集進行新增、修改、刪除資料時，有可能會發生無法更新實體集的例外狀況。以下是更新資料時所引發的錯誤訊息：&lt;br /&gt;&lt;blockquote&gt;System.Data.UpdateException: 無法更新 EntitySet '&lt;span style="font-style:italic;"&gt;實體集名稱&lt;/span&gt;'，因為它有 DefiningQuery，但是在 &amp;lt;ModificationFunctionMapping&amp;gt; 項目中沒有 &amp;lt;UpdateFunction&amp;gt; 項目來支援目前的作業。&lt;br /&gt;&lt;br /&gt;Unable to update the EntitySet '&lt;span style="font-style:italic;"&gt;EntitySet Name&lt;/span&gt;' because it has a DefiningQuery and no &amp;lt;UpdateFunction&amp;gt; element exists in the &amp;lt;ModificationFunctionMapping&amp;gt; element to support the current operation.&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;當你將不含主索引鍵的資料表加入實體資料模型（Entity Data Model，EDM）時，&lt;a href="http://zh.wikipedia.org/zh-tw/ADO.NET_Entity_Framework"&gt;Entity Framework&lt;/a&gt; 會因為找不到資料表主索引鍵，而將定義建立成唯讀的資料表，也就是在描述儲存結構之 SSDL 區段所定義的 &lt;a href="http://msdn.microsoft.com/zh-tw/library/bb387139.aspx"&gt;EntitySet 項目&lt;/a&gt;中，加入 &lt;a href="http://msdn.microsoft.com/zh-tw/library/bb738450.aspx"&gt;DefiningQuery 項目&lt;/a&gt;以對應到資料存放區的唯讀檢視。所以，當實體集使用定義查詢時，你就無法使用標準更新處理序將保存更新至資料來源。如果嘗試對唯讀的實體集進行更新動作，將會引發如上所述的例外狀況。&lt;br /&gt;&lt;br /&gt;要解決這個問題，你可以為來源資料表加入主索引鍵，並透過更新資料庫模型來獲得解決。或者，你也可以利用&lt;a href="http://msdn.microsoft.com/zh-tw/library/bb399203.aspx"&gt;實體資料模型支援使用預儲程序&lt;/a&gt;的功能，定義插入、更新、刪除函式對應來進行資料更新。&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/1506901775740741654/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/10/how-to-fix-unable-to-update-entityset.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/1506901775740741654" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/1506901775740741654" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/10/how-to-fix-unable-to-update-entityset.html" rel="alternate" title="How to Fix &quot;Unable to update the EntitySet&quot; Error" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-1445768515103807618</id><published>2009-09-11T11:35:00.019+08:00</published><updated>2010-07-04T16:51:42.089+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="ADO.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type="text">在 .NET 應用程式中執行 T-SQL 指令碼檔</title><content type="html">當你在 .NET 應用程式，使用 ADO.NET 提交包含 GO 指令的 T-SQL 批次時，SQL Server 會引發的語法不正確的錯誤。這是因為 GO 指令是 sqlcmd 、osql 等公用程式和 SQL Server 指令碼編輯器所認識的指令，而非有效的 T-SQL 陳述式。&lt;br /&gt;&lt;br /&gt;在執行含有一個以上 T-SQL 批次的指令碼時，SQL Server 公用程式會將 GO 視為 T-SQL 陳述式批次結束的信號，並將目前一個或多個 SQL 陳述式的集合傳送至 SQL Server，但並不包含 GO 指令。因此，當你使用 ADO.NET 執行多個 T-SQL 批次的指令碼時，你必須自行過濾 GO 指令，並分批執行 T-SQL 陳述式。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;如以下範例使用 &lt;a href="http://www.codeproject.com/KB/cs/embeddedresourcestrings.aspx"&gt;EmbeddedResourceTextReader&lt;/a&gt; 讀取內嵌資源的 SQL 指令碼檔內容，並透過 Regex 物件以 GO 關鍵字將指令碼分隔成批次陳述式，然後再逐一提交至 SQL Server 執行：&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;using System;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Data.SqlClient;&lt;br /&gt;using System.Configuration;&lt;br /&gt;using System.Text.RegularExpressions;&lt;br /&gt;&lt;br /&gt;namespace RunSql&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {            &lt;br /&gt;            string script = new EmbeddedResourceTextReader()&lt;br /&gt;                .GetFromResources("RunSql.Install.sql");&lt;br /&gt;                       &lt;br /&gt;            string[] stmts = Regex.Split(script, "\\sGO\\s", RegexOptions.IgnoreCase);&lt;br /&gt;&lt;br /&gt;            using (SqlConnection conn = &lt;br /&gt;                new SqlConnection(ConfigurationManager&lt;br /&gt;                    .ConnectionStrings["DefaultConnection"]&lt;br /&gt;                    .ConnectionString))&lt;br /&gt;            {&lt;br /&gt;                conn.Open();               &lt;br /&gt;                using (SqlTransaction trans =&lt;br /&gt;                    conn.BeginTransaction(IsolationLevel.ReadUncommitted))&lt;br /&gt;                {&lt;br /&gt;                    using (SqlCommand cmd = conn.CreateCommand())&lt;br /&gt;                    {&lt;br /&gt;                        cmd.Transaction = trans;                        &lt;br /&gt;                        cmd.CommandType = CommandType.Text;&lt;br /&gt;                                                &lt;br /&gt;                        foreach (string stmt in stmts)&lt;br /&gt;                        {&lt;br /&gt;                            cmd.CommandText = stmt.Trim();&lt;br /&gt;                            if (cmd.CommandText.Length &amp;gt; 0)&lt;br /&gt;                            {                                &lt;br /&gt;                                try&lt;br /&gt;                                {&lt;br /&gt;                                    cmd.ExecuteNonQuery();&lt;br /&gt;                                }&lt;br /&gt;                                catch(SqlException) &lt;br /&gt;                                {&lt;br /&gt;                                    trans.Rollback();&lt;br /&gt;                                    throw;&lt;br /&gt;                                }&lt;br /&gt;                            }                            &lt;br /&gt;                        }&lt;br /&gt;                    }                                        &lt;br /&gt;                    trans.Commit();&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;相較於 ADO.NET，使用 SQL Server Management Objects（SMO）就無須處理 GO 指令的問題，使用起來更為簡便。有關如何使用 SMO 執行 T-SQL 批次的範例程式碼，請參閱&lt;a href="http://weblogs.asp.net/jgalloway/archive/2006/11/07/Handling-_2200_GO_2200_-Separators-in-SQL-Scripts-_2D00_-the-easy-way.aspx"&gt;這裡&lt;/a&gt;。&lt;br /&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/1445768515103807618/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/09/executing-t-sql-scripts-with-net.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/1445768515103807618" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/1445768515103807618" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/09/executing-t-sql-scripts-with-net.html" rel="alternate" title="在 .NET 應用程式中執行 T-SQL 指令碼檔" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-4666289795608878182</id><published>2009-07-22T14:15:00.067+08:00</published><updated>2010-07-04T17:09:38.638+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AJAX"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type="text">Using DHTML Tooltips with AJAX</title><content type="html">&lt;a href="http://www.walterzorn.com/tooltip/tooltip_e.htm"&gt;DHTML Tooltips&lt;/a&gt; 是一個跨瀏覽器相容的程式庫，提供豐富的功能讓你可以輕鬆建立、自訂多樣的工具提示（Tooltip）或是彈跳式訊息（Pup-up Box）。&lt;br /&gt;&lt;br /&gt;程式庫提供 &lt;span style="font-style:italic;"&gt;Tip&lt;/span&gt; 函式接受訊息字串參數，而 &lt;span style="font-style:italic;"&gt;TagToTip&lt;/span&gt; 函式則允許你提供元素的識別名稱以顯示其 HTML 的內容。這兩個函式的用法都相當簡單，在此就不再贅述，本文將會側重在兩者的併用，並透過範例逐步說明告訴你，如何結合 &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; 的應用來動態載入伺服器所提供的提示訊息。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;在以下的範例網頁片段中，你會看到座位平面圖，以及其所組成映射區域，並且繫結要實作動態提示訊息的 &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; 事件處理函式。&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;img src="Images/seatingplan.png" usemap="#seatingPlan" /&amp;gt;&lt;br /&gt;&amp;lt;map name="seatingPlan"&amp;gt;&lt;br /&gt;    &amp;lt;area shape="rect" id="Front Stalls" coords="22,100,493,236" &lt;br /&gt;        onmouseover="showSectionInfo(this, 61);" /&amp;gt;&lt;br /&gt;    &amp;lt;area shape="rect" id="Rear Stalls" coords="22,252,492,388" &lt;br /&gt;        onmouseover="showSectionInfo(this, 62);" /&amp;gt;&lt;br /&gt;&amp;lt;/map&amp;gt;&lt;/pre&gt;&lt;br /&gt;在定義 &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; 事件處理函式之前，我們先在 jQuery 的 DOM &lt;span style="font-style:italic;"&gt;ready&lt;/span&gt; 事件中，預先建立一個供資料讀取的過程中顯示處理訊息的隱藏區塊，並將 Tooltips 程式庫中的 &lt;span style="font-style:italic;"&gt;UnTip&lt;/span&gt; 函式繫結所有映射區域元素的 &lt;span style="font-style:italic;"&gt;onmouseout&lt;/span&gt; 事件處理常式。&lt;pre class="prettyprint"&gt;$(document).ready(function() {&lt;br /&gt;    $('&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;')&lt;br /&gt;    .attr('id', 'ajaxLoading')&lt;br /&gt;    .html('Loading...')&lt;br /&gt;    .hide()&lt;br /&gt;    .appendTo('body');&lt;br /&gt;&lt;br /&gt;    $("map[name='seatingPlan'] *")&lt;br /&gt;    .mouseout(UnTip);&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;當映射區域元素 &lt;span style="font-style:italic;"&gt;onmouseover&lt;/span&gt; 事件被觸發時，將會執行以下函式並將所接收的傳遞參數做為請求參數，來進行遠端呼叫：&lt;br /&gt;&lt;pre class="prettyprint"&gt;function showSectionInfo(element, sectionId) {&lt;br /&gt;    if (data(element) === undefined) {&lt;br /&gt;        tooltip.call(element, 'ajaxLoading');&lt;br /&gt;        $.ajax({&lt;br /&gt;            url: 'InfoHandler.ashx',&lt;br /&gt;            type: 'GET',&lt;br /&gt;            data: {&lt;br /&gt;                id: sectionId&lt;br /&gt;            },&lt;br /&gt;            dataType: 'html',&lt;br /&gt;            error: function(xhr) {&lt;br /&gt;                UnTip();&lt;br /&gt;                alert('The ajax request failed.');&lt;br /&gt;            },&lt;br /&gt;            success: function(response) {&lt;br /&gt;                data(element, response);&lt;br /&gt;                tooltip.call(element);&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;    } else {&lt;br /&gt;        tooltip.call(element);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;在叫用 jQuery 的 &lt;span style="font-style:italic;"&gt;ajax&lt;/span&gt; 函式處理非同步請求前，會先透過以下所定義的 &lt;span style="font-style:italic;"&gt;tooltip&lt;/span&gt; 函式叫用 &lt;span style="font-style:italic;"&gt;TagToTip&lt;/span&gt; 函式將先前所建立的隱藏訊息顯示出來，以回應使用者的請求：&lt;br /&gt;&lt;pre class="prettyprint"&gt;function tooltip(elementId) {&lt;br /&gt;    var options = [ABOVE, true, SHADOW, true];&lt;br /&gt;    if (elementId === undefined) {&lt;br /&gt;        Tip.apply(this, $.merge([data(this)], options));&lt;br /&gt;    } else {&lt;br /&gt;        TagToTip.apply(this, $.merge([elementId], options));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;當 AJAX 請求成功後，會透過如下的 &lt;span style="font-style:italic;"&gt;data&lt;/span&gt; 函式將回應結果暫存到元素物件中，提供給後續可能的相同觸發動作讀取之用，以避免冗餘的資料請求。&lt;br /&gt;&lt;pre class="prettyprint"&gt;function data(element, value) {&lt;br /&gt;    return value === undefined ? $.data(element, 'tooltip') :&lt;br /&gt;        $.data(element, 'tooltip', value);&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;最後，再次呼叫 &lt;span style="font-style:italic;"&gt;tooltip&lt;/span&gt; 函式將回應結果委由 &lt;span style="font-style:italic;"&gt;Tip&lt;/span&gt; 函式顯示出來。&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/4666289795608878182/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/07/using-dhtml-tooltips-with-ajax.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4666289795608878182" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4666289795608878182" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/07/using-dhtml-tooltips-with-ajax.html" rel="alternate" title="Using DHTML Tooltips with AJAX" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-4173663503122396772</id><published>2009-07-19T14:03:00.059+08:00</published><updated>2010-07-04T17:25:15.161+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><category scheme="http://www.blogger.com/atom/ns#" term="Plugin"/><title type="text">jQuery Floating Layer Plugin</title><content type="html">在許多網站設計中，浮動圖層（Floating Layer）經常被應用在較長的網頁文件中，以呈現能隨著瀏覽器的捲軸移動的浮動廣告或選單。&lt;br /&gt;&lt;br /&gt;Floating Layer Plugin 是以 jQuery 原型物件（Prototype Object）為基礎所擴充的外掛程式庫。相較於先前版本，這次的版本除了將程式碼最佳化外，也增添了若干的新功能。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;makeFloating( [options] )&lt;/span&gt;&lt;br /&gt;透過元素選取（Selector）將特定的 DOM 元素封裝為具有 jQuery 函式功能的外覆物件後，你可以呼叫此函式來建立自訂的浮動圖層。函式可以接受傳遞物件參數來提供選項設定屬性，如以下所示：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th&gt;屬性&lt;/th&gt;&lt;th&gt;型別&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td valign="top"&gt;&lt;span style="font-weight:bold;"&gt;position&lt;/span&gt;&lt;/td&gt;&lt;td valign="top"&gt;object&lt;/td&gt;&lt;td&gt;指定 x 和 y 屬性來控制浮動區塊的定位方式。除了絕對座標來定位外，你也可以在 x 軸指定 "left"、"right"、"center" 決定水平位置，在 y 軸指定 "top"、"bottom"、"center" 來決定垂直位置。&lt;br /&gt;範例：&lt;ul&gt;&lt;li&gt;{x:0, y:250}&lt;/li&gt;&lt;li&gt;{x:'right', y:'top'}&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;duration&lt;/span&gt;&lt;/td&gt;&lt;td&gt;number&lt;/td&gt;&lt;td&gt;指定動畫的顯示速度，以毫秒為單位。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;easing&lt;/span&gt;&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;指定變速移動的特效。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;fixed&lt;/span&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;指定是否要固定圖層位置而不隨捲軸移動。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;應用範例&lt;/span&gt;&lt;br /&gt;首先，除了必要的 &lt;a href="http://docs.jquery.com/Downloading_jQuery"&gt;jQuery&lt;/a&gt; 程式庫外，你還需要&lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/jquery.floatinglayer.zip"&gt;下載&lt;/a&gt;本程式庫並引入到你的網頁中。然後，在網頁的文件的主體中加入區塊圖層，如以下範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;div id="floatlayer" style="&lt;br /&gt;    width: 50px;&lt;br /&gt;    height: 50px;&lt;br /&gt;    border: solid 1px #cccccc; &lt;br /&gt;    background-color: #d0d0ff;&lt;br /&gt;    z-index: 100;&lt;br /&gt;    display: none"&amp;gt;&lt;br /&gt;    &amp;lt;!-- Place your content here --&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;br /&gt;接下來，你可以處理 jQuery 的 DOM &lt;span style="font-style:italic;"&gt;ready&lt;/span&gt; 事件，在網頁載入完成後，選取如上的圖層元素並叫用 &lt;span style="font-style:italic;"&gt;makeFloating&lt;/span&gt; 函式：&lt;br /&gt;&lt;pre class="prettyprint"&gt;$(document).ready(function() {&lt;br /&gt;    $('#floatlayer').makeFloating();&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;在預設的情況下，浮動圖層會配合網頁的可見區域以水平置左、垂直置中的方式定位，且會隨瀏覽器的捲軸移動產生擺動（Swing）的動畫效果。如果要變更浮動圖層的預設行為，你可以透過物件參數提供自訂的選項設定。如以下範例會建立水平置右、垂直置中，並加入線性（Linear）動畫效果的浮動圖層： &lt;br /&gt;&lt;pre class="prettyprint"&gt;$('#floatlayer').makeFloating({&lt;br /&gt;    position: { x: 'right', y: 'center' },&lt;br /&gt;    easing: 'linear'&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;因為程式所表現的動畫效果是透過 jQuery 的 &lt;span style="font-style:italic;"&gt;animate&lt;/span&gt; 函式來實現，所以 &lt;span style="font-style:italic;"&gt;easing&lt;/span&gt; 參數只能支援內建的 &lt;span style="font-style:italic;"&gt;linear&lt;/span&gt;、&lt;span style="font-style:italic;"&gt;swing&lt;/span&gt; 兩種特效。如果內建的動畫效果不能符合你的期望，建議你可以搭配 &lt;a href="http://gsgd.co.uk/sandbox/jquery/easing/"&gt;Easing Plugin&lt;/a&gt; 來擴增多種慢入（Easing In）和慢出（Easing Out）的動畫效果，如以下範例就使用了更為順暢的慢出特效：&lt;br /&gt;&lt;pre class="prettyprint"&gt;$('#floatlayer').makeFloating({&lt;br /&gt;    position: { x: 'right', y: 'center' },&lt;br /&gt;    easing: 'easeOutBounce'&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;當然，如果你不需要動態移動的效果，你也可以透過物件參數的 &lt;span style="font-style:italic;"&gt;fixed&lt;/span&gt; 屬性來固定圖層的位置：&lt;br /&gt;&lt;pre class="prettyprint"&gt;$('#floatlayer').makeFloating({&lt;br /&gt;    position: { x: 'right', y: 'center' },&lt;br /&gt;    fixed: true&lt;br /&gt;});&lt;/pre&gt;&lt;br /&gt;另外，程式庫還提供 &lt;span style="font-style:italic;"&gt;floatingPosition&lt;/span&gt; 函式，讓你可以在建立浮動圖層物件後，重新定位浮動的目標位置，如以下範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;$('#floatlayer').floatingPosition({ x: 'center', y: 'center' });&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/jquery.floatinglayer.zip"&gt;Download jquery.floatinglayer.zip&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/4173663503122396772/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/07/jquery-floating-layer-plugin.html#comment-form" rel="replies" title="3 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4173663503122396772" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4173663503122396772" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/07/jquery-floating-layer-plugin.html" rel="alternate" title="jQuery Floating Layer Plugin" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s72-c/download.gif" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-8942281008461401575</id><published>2009-06-17T17:20:00.105+08:00</published><updated>2009-07-07T14:26:59.532+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Chrome"/><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><title type="text">在 Chrome 2.0 中為 JavaScript 偵錯</title><content type="html">和大多數人一樣，瀏覽器本身對我來說並不重要，它只是瀏覽網頁、使用網路應用的工具而已。相較於瀏覽器的功能性，快速、穩定的基本要素更能貼近我的需求。因此，強調簡潔、快速的 Google Chrome 瀏覽器，很快就在我心中佔據了一個無可取代的地位。&lt;br /&gt;&lt;br /&gt;Chrome 不僅滿足使用者對瀏覽器的根本訴求，也從開發人員需求實務上的觀點設計許多的功能，希望能藉以協助開發人員提供更好的使用者經驗。在開發人員的工具中，最令我感興趣的，卻也是對我極度不友善而讓我望之卻步的，莫過於基於命令提示介面的 JavaScript 偵錯工具（JavaScript Debugger）了。當然，這對於既自詡為 Chrome 愛用者，又身兼網頁開發人員的我來說，似乎令人難以悅服。於是，最近我又再度興起要深入研究這個好用的小工具的念頭，如今在此分享自己的學習心得及蒐集的相關資訊，希望能對有興趣的朋友有所幫助。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;命令&lt;/span&gt;&lt;br /&gt;在 JavaScript 偵錯工具中，可使用的命令會依目前是否處於執行中或是中斷狀態而有所不同。在執行狀態中，也就是網頁尚未執行暫止於中斷點時的狀態下，可以使用的命令如下：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th width="50%"&gt;命令&lt;/th&gt;&lt;th width="50%"&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;b&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;reak&lt;/span&gt;] &amp;lt;&lt;span style="font-style:italic;"&gt;function&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:function&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:line&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:line:pos&lt;/span&gt;&amp;gt; [&lt;span style="font-style:italic;"&gt;condition&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;在來源中的位置或函式設定中斷點。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;break_info&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;]&lt;br/&gt;或&lt;br/&gt;&lt;span style="font-weight:bold;"&gt;bi&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;顯示目前所有中斷點資訊，或是已指定中斷點的資訊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;clear&lt;/span&gt; &amp;lt;&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;移除已指定的中斷點。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;h&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;elp&lt;/span&gt;] [&lt;span style="font-style:italic;"&gt;command&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;顯示所有命令的描述，或是已指定命令的詳細描述。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;p&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;rint&lt;/span&gt;] &amp;lt;&lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;評估運算式並輸出執行結果。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;scripts&lt;/span&gt;&lt;/td&gt;&lt;td&gt;顯示所有可偵錯的指令碼資訊。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;smaller&gt;&lt;span style="font-style:italic;"&gt;註：[] 表示可省略或選擇性項目； &amp;lt;&amp;gt; 表示必須提供的項目。&lt;/span&gt;&lt;/smaller&gt;&lt;br /&gt;&lt;br /&gt;當網頁暫止於中斷點的狀態時，可以使用的命令如下：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th width="50%"&gt;命令&lt;/th&gt;&lt;th width="50%"&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;args&lt;/span&gt;&lt;/td&gt;&lt;td&gt;顯示目前函數的參數。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;b&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;reak&lt;/span&gt;] [&amp;lt;&lt;span style="font-style:italic;"&gt;function&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:function&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:line&lt;/span&gt; | &lt;span style="font-style:italic;"&gt;script:line:pos&lt;/span&gt;&amp;gt; [&lt;span style="font-style:italic;"&gt;condition&lt;/span&gt;]]&lt;/td&gt;&lt;td&gt;在來源中的位置或函式設定中斷點，或是不使用任何參數停止偵錯並終止程式執行。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;break_info&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;]&lt;br/&gt;或&lt;br/&gt;&lt;span style="font-weight:bold;"&gt;bi&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;顯示目前所有中斷點資訊，或是已指定中斷點的資訊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;backtrace&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;from frame #&lt;/span&gt;] [&lt;span style="font-style:italic;"&gt;to frame #&lt;/span&gt;]&lt;br/&gt;或&lt;br/&gt;&lt;span style="font-weight:bold;"&gt;bt&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;from frame #&lt;/span&gt;] [&lt;span style="font-style:italic;"&gt;to frame #&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;顯示目前函式的呼叫堆疊（Call Stack）。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;clear&lt;/span&gt; &amp;lt;&lt;span style="font-style:italic;"&gt;breakpoint #&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;移除已指定的中斷點。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;c&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;ontinue&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;繼續執行到下一個中斷點。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;dir&lt;/span&gt; &amp;lt;&lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;顯示物件的詳細資訊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;f&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;rame&lt;/span&gt;] &amp;lt;&lt;span style="font-style:italic;"&gt;frame #&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;顯示目前堆疊框架（Stack Frame）的偵錯資訊，或是已指定堆疊框架的偵錯資訊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;h&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;elp&lt;/span&gt;] [&lt;span style="font-style:italic;"&gt;command&lt;/span&gt;]&lt;br/&gt;或&lt;br/&gt;? [&lt;span style="font-style:italic;"&gt;command&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;顯示所有命令的描述，或是已指定命令的詳細描述。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;locals&lt;/span&gt;&lt;/td&gt;&lt;td&gt;顯示目前堆疊框架中所有變數的值。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;n&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;ext&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;逐步執行每行指令碼，如果是執行函式呼叫，則會進入函式內的第一行指令碼。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;p&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;rint&lt;/span&gt;] &amp;lt;&lt;span style="font-style:italic;"&gt;expression&lt;/span&gt;&amp;gt;&lt;/td&gt;&lt;td&gt;評估運算式並輸出執行結果。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;scripts&lt;/span&gt;&lt;/td&gt;&lt;td&gt;顯示所有可偵錯的指令碼資訊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;source&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;from line&lt;/span&gt;] | [&amp;lt;&lt;span style="font-style:italic;"&gt;from line&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style="font-style:italic;"&gt;num lines&lt;/span&gt;&amp;gt;]&lt;br/&gt;或&lt;br/&gt;&lt;span style="font-weight:bold;"&gt;ls&lt;/span&gt; [&lt;span style="font-style:italic;"&gt;from line&lt;/span&gt;] | [&amp;lt;&lt;span style="font-style:italic;"&gt;from line&lt;/span&gt;&amp;gt; &amp;lt;&lt;span style="font-style:italic;"&gt;num lines&lt;/span&gt;&amp;gt;]&lt;/td&gt;&lt;td&gt;顯示目前堆疊框架的原始碼，或從指定的行號開始顯示。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;s&lt;/span&gt;[&lt;span style="font-weight:bold;"&gt;tep&lt;/span&gt;]&lt;/td&gt;&lt;td&gt;逐步執行每行指令碼，如果是執行函式呼叫，則不會進入函式直接執行。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span style="font-weight:bold;"&gt;stepout&lt;/span&gt;&lt;br/&gt;或&lt;br/&gt;&lt;span style="font-weight:bold;"&gt;so&lt;/span&gt;&lt;/td&gt;&lt;td&gt;在目前的函式中，繼續執行指令碼直到函式返回，然後在呼叫函式的返回點中斷。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;範例網頁&lt;/span&gt;&lt;br /&gt;為了幫助你更快熟悉偵錯命令的應用，將會利用以下範例網頁，用逐步解說的的方式進行偵錯示範。&lt;br /&gt;&lt;pre&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Sample Page&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript" src="shape.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;     &lt;br /&gt;    function Rectangle(x, y, w, h, cnv) {&lt;br /&gt;        Shape.call(this, x, y);&lt;br /&gt;        this.width = w;&lt;br /&gt;        this.height = h;&lt;br /&gt;        this.convas = cnv;&lt;br /&gt;        return true;&lt;br /&gt;    }    &lt;br /&gt;    &lt;br /&gt;    Rectangle.prototype = new Shape();&lt;br /&gt;    Rectangle.prototype.draw = function() {&lt;br /&gt;        if(this.convas) {&lt;br /&gt;            this.convas.innerHTML += "Drawing a Rectangle at:" + this.getCoordinates() +&lt;br /&gt;                    ", width " + this.width + ", height " + this.height + "&amp;lt;br/&amp;gt;";&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    function drawRectangle() {&lt;br /&gt;        var x = parseInt(document.getElementById("x").value);&lt;br /&gt;        var y = parseInt(document.getElementById("y").value);&lt;br /&gt;        var w = parseInt(document.getElementById("w").value);&lt;br /&gt;        var h = parseInt(document.getElementById("h").value);&lt;br /&gt;        var cnv = document.getElementById("cnv");&lt;br /&gt;        var rect = new Rectangle(x, y, w, h, cnv);&lt;br /&gt;        rect.draw();&lt;br /&gt;    }&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    x:&amp;lt;input id="x" type="text" size="3" /&amp;gt; y:&amp;lt;input id="y" type="text" size="3" /&amp;gt;&lt;br /&gt;    width:&amp;lt;input id="w" type="text" size="3" /&amp;gt; height:&amp;lt;input id="h" type="text" size="3" /&amp;gt;&lt;br /&gt;    &amp;lt;input type="button" value="Draw Rectangle" onclick="javascript:drawRectangle();" /&amp;gt;&lt;br /&gt;    &amp;lt;div id="cnv"&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;在範例網頁中引入一個外部的 js 檔案，其內容如下：&lt;br /&gt;&lt;pre&gt;function Shape(x, y) {&lt;br /&gt;    this.x = x;&lt;br /&gt;    this.y = y;&lt;br /&gt;    return true;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Shape.prototype = {&lt;br /&gt;    getCoordinates : function() {&lt;br /&gt;        return "(" + this.x + " ," + this.y + ")";&lt;br /&gt;    }&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;當你在 Chrome 中開啟範例網頁後，請按一下 [網頁功能] 功能表，然後在 [開發人員選項] 點選 [為 JavaScript 偵錯] 或是使用鍵盤捷徑 [Ctrl+Shift+L]，這時 JavaScript 偵錯工具便會開啟並附加在作用中的分頁。另外，你還需要 [檢視網頁原始碼]，除了便於在偵錯期間檢視程式碼外，也可以利用原始碼的行號來設定中斷點。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzoxaAIaHH4VaX82XIydosybpD8mx9x6i5lD4X9c4_Fe2lQKmRa27Mp6IE9eQE8Z8SbnBlS_JElu_iH0N6ozgtgeg-i7EweD5hMBaon9qe57Yh-0o4LXaf9pqsyHvsuRFrPh6PSig5lyM/s1600-h/debugger.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 236px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzoxaAIaHH4VaX82XIydosybpD8mx9x6i5lD4X9c4_Fe2lQKmRa27Mp6IE9eQE8Z8SbnBlS_JElu_iH0N6ozgtgeg-i7EweD5hMBaon9qe57Yh-0o4LXaf9pqsyHvsuRFrPh6PSig5lyM/s320/debugger.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5349978002739772114" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;偵錯逐步解說&lt;/span&gt;&lt;br /&gt;在進行偵錯前，我們可以在命令列輸入 "scripts" 來檢視附加在範例網頁的指令碼資訊，如以下輸出結果：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;scripts&lt;/span&gt;&lt;br /&gt;file:///C:/shape.js (lines 11)&lt;br /&gt;file:///C:/test.htm (lines 4-30)&lt;br /&gt;[unnamed] (source:"javascript:void(0)")&lt;/pre&gt;&lt;br /&gt;如果你要將中斷點設在外部檔案中的 Shape 建構函式，你可以執行如下的命令：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;break Shape&lt;/span&gt;&lt;br /&gt;set breakpoint #1&lt;/pre&gt;&lt;br /&gt;除了指定函式中斷點外，你也可以指定原始碼的位置來設定中斷點。例如，若要將中斷點設在如下的指令碼行：&lt;br /&gt;&lt;pre&gt;var rect = new Rectangle(x, y, w, h, cnv);&lt;/pre&gt;&lt;br /&gt;那麼，你可以先從 [檢視網頁原始碼] 中得知指令碼行所在行號，然後執行如下的命令：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;break file:///C:/test.htm:28&lt;/span&gt;&lt;br /&gt;set breakpoint #2&lt;/pre&gt;&lt;br /&gt;然而，上述設定中斷點的方式都屬於無條件中斷，事實上，你還可以選擇性地設定需同時符合特定條件的中斷點：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;break file:///C:/test.htm:24 x&amp;lt;0&lt;/span&gt;&lt;br /&gt;set breakpoint #3&lt;/pre&gt;&lt;br /&gt;這個命令將會在以下的原始碼位置設定中斷點，且變數 x 的值必須滿足特定條件才會暫止程式執行。&lt;br /&gt;&lt;pre&gt;var y = parseInt(document.getElementById("y").value);&lt;/pre&gt;&lt;br /&gt;當你完成如上的中斷點設定後，便可以使用 "break_info" 檢視所有的中斷點資訊：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;break_info&lt;/span&gt;&lt;br /&gt;Num breakpoints: 3&lt;br /&gt;id=1, hit_count=0, type=function, target=Shape&lt;br /&gt;id=2, hit_count=0, type=script, target=file:///C:/test.htm, line=27&lt;br /&gt;id=3, hit_count=0, type=script, target=file:///C:/test.htm, line=23, condition=x&amp;lt;0&lt;/pre&gt;&lt;br /&gt;現在，你可以回到範例網頁的頁籤，然後填入必要欄位並按下按紐執行指令碼。如果你在 x 欄位輸入的數值小於零的話，那麼程式就會暫止在第三個中斷點：&lt;br /&gt;&lt;pre&gt;paused at breakpoint 3: drawRectangle(), file:///C:/test.htm&lt;br /&gt;24:         var y = parseInt(document.getElementById("y").value);&lt;/pre&gt;&lt;br /&gt;若要繼續執行指令碼，可以視情況選擇使用 "step" 或 "next" 命令來逐行執行指令碼：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;next&lt;/span&gt;&lt;br /&gt;25:         var w = parseInt(document.getElementById("w").value);&lt;/pre&gt;&lt;br /&gt;或是，使用 "continue" 命令繼續執行到下一個中斷點，也就是之前所設定的第二個中斷點：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;continue&lt;/span&gt;&lt;br /&gt;paused at breakpoint 2: drawRectangle(), file:///C:/test.htm&lt;br /&gt;28:         var rect = new Rectangle(x, y, w, h, cnv);&lt;/pre&gt;&lt;br /&gt;當程式中斷執行時，可以輸入 "locals" 命令來檢視目前執行函數中的所有變數值：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;locals&lt;/span&gt;&lt;br /&gt;w = 400&lt;br /&gt;cnv = #&amp;lt;an HTMLDivElement&amp;gt;&lt;br /&gt;x = -10&lt;br /&gt;y = 0&lt;br /&gt;h = 600&lt;br /&gt;rect = undefined&lt;/pre&gt;&lt;br /&gt;若程式繼續執行，將會暫止在第一個中斷點：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;continue&lt;/span&gt;&lt;br /&gt;paused at breakpoint 1: #&lt;an Object&gt;.Shape(x=-10, y=0), file:///C:/shape.js&lt;br /&gt;2:     this.x = x;&lt;/pre&gt;&lt;br /&gt;在偵錯過程中，你可以選擇性地切換堆疊框架來進行偵錯。首先，你可以透過 "backtrace" 命令來檢視所有堆疊框架的資訊：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;backtrace&lt;/span&gt;&lt;br /&gt;Frames #0 to #4 of 5:&lt;br /&gt;#00 #&amp;lt;an Object&amp;gt;.Shape(x=-10, y=0) file:///C:/shape.js line 2 column 12 (position 36)&lt;br /&gt;#01 new Rectangle(x=-10, y=0, w=400, h=300, cnv=#&amp;lt;an HTMLDivElement&amp;gt;) file:///C:/test.htm line 7 column 15 (position 58)&lt;br /&gt;#02 drawRectangle() file:///C:/test.htm line 28 column 20 (position 839)&lt;br /&gt;#03 #&amp;lt;an HTMLInputElement&amp;gt;.[anonymous](evt=#&amp;lt;a MouseEvent&amp;gt;) file:///C:/test.htm line 37 column 12 (position 177)&lt;br /&gt;#04 #&amp;lt;an HTMLInputElement&amp;gt;.onclick(evt=#&amp;lt;a MouseEvent&amp;gt;) file:///C:/test.htm line 38 column 4 (position 197)&lt;/pre&gt;&lt;br /&gt;然後，再使用 "frame" 的命令來切換到指定的堆疊框架，如以下所示：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;frame 1&lt;/span&gt;&lt;br /&gt;#01 Rectangle, undefined&lt;br /&gt;7:         Shape.call(this, x, y);&lt;/pre&gt;&lt;br /&gt;你可以視需要使用 "source" 命令來檢視目前堆疊框架的原始碼：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;source&lt;/span&gt;&lt;br /&gt; 5: &lt;br /&gt; 6:     function Rectangle(x, y, w, h, cnv) {&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;        Shape.call(this, x, y);&lt;br /&gt; 8:         this.width = w;&lt;br /&gt; 9:         this.height = h;&lt;br /&gt;10:         this.convas = cnv;&lt;br /&gt;11:         return true;&lt;br /&gt;12:     }&lt;/pre&gt;&lt;br /&gt;如果不打算繼續執行指令碼，請使用 "break" 命令停止偵錯並終止程式執行：&lt;br /&gt;&lt;pre&gt;$ &lt;span style="font-weight:bold;"&gt;break&lt;/span&gt;&lt;br /&gt;JavaScript execution already stopped.&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.alexatnet.com/node/180"&gt;Sample debug session with Google Chrome JavaScript debuger&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.pascarello.com/lessons/browsers/ChromeDebugHelp.html"&gt;Basic information on Chrome's Debugger&lt;/a&gt;&lt;br /&gt;&lt;a href="http://d.hatena.ne.jp/Syunpei/20080904/1220500815"&gt;Google Chrome JavaScriptデバッガ完全マニュアル&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/8942281008461401575/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/06/using-javascript-debugger-in-chrome.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8942281008461401575" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8942281008461401575" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/06/using-javascript-debugger-in-chrome.html" rel="alternate" title="在 Chrome 2.0 中為 JavaScript 偵錯" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzoxaAIaHH4VaX82XIydosybpD8mx9x6i5lD4X9c4_Fe2lQKmRa27Mp6IE9eQE8Z8SbnBlS_JElu_iH0N6ozgtgeg-i7EweD5hMBaon9qe57Yh-0o4LXaf9pqsyHvsuRFrPh6PSig5lyM/s72-c/debugger.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-6821084121963288241</id><published>2009-04-16T10:50:00.040+08:00</published><updated>2010-07-04T16:50:19.268+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="CKIP"/><title type="text">CKIP Client for .NET</title><content type="html">&lt;a href="http://ckipsvr.iis.sinica.edu.tw/"&gt;CKIP 中文斷詞系統&lt;/a&gt;是由中文詞知識庫小組（Chinese Knowledge Information Processing Group，CKIP）所發展的線上斷詞服務。此服務採用 XML 資料交換模式，用戶端必須自行撰寫程式經由 TCP Scoket 傳送文本到斷詞系統，並剖析回傳包含斷詞及詞類標記的 XML 處理結果。&lt;br /&gt;&lt;br /&gt;目前，&lt;a href="http://ckipclient.sourceforge.net/"&gt;CKIP Client&lt;/a&gt; 開放原始碼專案已實作 Java、PHP 兩種版本，可以用來簡化 CKIP 斷詞服務用戶端應用程式的開發，而不需自行撰寫 Socket 程式碼及處理 XML 資料。而本文的 CKIP Client for .NET 則是自己重新以 C# 實作 CLR 非同步程式撰寫模型（Asynchronous Programming Model）所設計的斷詞服務用戶端 APIs。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;使用範例&lt;/span&gt;&lt;br /&gt;下列範例會使用 CkipClient 在同步封鎖模式進行連接、傳送文本，並接收傳回結果，其中 username 及 password 為用戶端所申請之帳號及密碼。&lt;br /&gt;&lt;pre class="prettyprint"&gt;using (CkipClient client = new CkipClient("username", "password"))&lt;br /&gt;{&lt;br /&gt;    client.Send("菩提本無樹，明鏡亦非臺；本來無一物，何處惹塵埃？");&lt;br /&gt;    SegmentationResult result = client.GetResult();&lt;br /&gt;&lt;br /&gt;    if (result.StatusCode == StatusCode.Success)&lt;br /&gt;    {&lt;br /&gt;        StringBuilder sb = new StringBuilder();&lt;br /&gt;        foreach (Term term in result.GetTerms())&lt;br /&gt;        {&lt;br /&gt;            sb.Append(term.ToString() + "　");&lt;br /&gt;        }&lt;br /&gt;        Console.WriteLine(sb.ToString());&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine(string.Format("Error: {0}", result.StatusDescription));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;輸出結果如下：&lt;br /&gt;&lt;pre&gt;菩提(N)　本無樹(N)　，(COMMACATEGORY)　明鏡(N)　亦(ADV)　非(Vt)　臺(N)　；(SEMICOLONCATEGORY)　本來(ADV)　無(Vt)　一(DET)　物(N)　，(COMMACATEGORY)　何處(N)　惹(Vt)　塵埃(N)　？(QUESTIONCATEGORY)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;非同步 API 使用範例&lt;/span&gt;&lt;br /&gt;&lt;pre style="height:350px; overflow:auto" class="prettyprint"&gt;using System;&lt;br /&gt;using System.Collections.Generic;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Text;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;using CKIP;&lt;br /&gt;&lt;br /&gt;namespace AsyncCkipClient&lt;br /&gt;{&lt;br /&gt;    public partial class MainForm : Form&lt;br /&gt;    {&lt;br /&gt;        public MainForm()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void uxSend_Click(object sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            CkipClient client = new CkipClient();            &lt;br /&gt;            client.BeginConnect(uxUsername.Text, uxPassword.Text, &lt;br /&gt;                new AsyncCallback(EndConnectCallback), client);&lt;br /&gt;            DisplayStatus("Connecting to server ...");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void EndConnectCallback(IAsyncResult ar)&lt;br /&gt;        {&lt;br /&gt;            CkipClient client = (CkipClient)ar.AsyncState;&lt;br /&gt;            &lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                client.EndConnect(ar);&lt;br /&gt;&lt;br /&gt;                if (client.Connected)&lt;br /&gt;                {&lt;br /&gt;                    client.BeginSend(uxRawText.Text, &lt;br /&gt;                        new AsyncCallback(EndSendCallback), client);&lt;br /&gt;                    DisplayStatus("Sending data to server ...");             &lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                    DisplayStatus(string.Format("Ready (last error: {0})", "Connect Failed!"));&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                client.Close();&lt;br /&gt;                DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void EndSendCallback(IAsyncResult ar)&lt;br /&gt;        {&lt;br /&gt;            CkipClient client = (CkipClient)ar.AsyncState;&lt;br /&gt;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                client.EndSend(ar);                &lt;br /&gt;                client.BeginGetResult(new AsyncCallback(EndGetResultCallback), client);&lt;br /&gt;                DisplayStatus("Reading server response ...");&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                client.Close();&lt;br /&gt;                DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void EndGetResultCallback(IAsyncResult ar)&lt;br /&gt;        {&lt;br /&gt;            CkipClient client = (CkipClient)ar.AsyncState;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                SegmentationResult result = client.EndGetResult(ar);&lt;br /&gt;&lt;br /&gt;                if (result.StatusCode == StatusCode.Success)&lt;br /&gt;                {&lt;br /&gt;                    StringBuilder sb = new StringBuilder();&lt;br /&gt;                    foreach (Term term in result.GetTerms())&lt;br /&gt;                    {&lt;br /&gt;                        sb.Append(term.ToString() + "　");&lt;br /&gt;                    }&lt;br /&gt;                    DisplayResults(sb.ToString());&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {                    &lt;br /&gt;                    DisplayStatus(string.Format("Ready (last error: {0})", &lt;br /&gt;                        result.StatusDescription));&lt;br /&gt;                }                &lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {                &lt;br /&gt;                DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));&lt;br /&gt;            }&lt;br /&gt;            finally&lt;br /&gt;            {&lt;br /&gt;                client.Close();&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void DisplayResults(string text)&lt;br /&gt;        {&lt;br /&gt;            if (InvokeRequired)&lt;br /&gt;            {&lt;br /&gt;                BeginInvoke(new Action&amp;lt;string&amp;gt;(DisplayResults), text);&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            uxResult.Text = text;&lt;br /&gt;            DisplayStatus("Done");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void DisplayStatus(string text)&lt;br /&gt;        {&lt;br /&gt;            if (InvokeRequired)&lt;br /&gt;            {&lt;br /&gt;                BeginInvoke(new Action&amp;lt;string&amp;gt;(DisplayStatus), text);&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;            uxStatus.Text = text;&lt;br /&gt;        }        &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHK6vuFwf29EAQQnlec4pYz2UZXtkuqe2j4CKCsN39LGJiQPFM4Ix4jXAsby2DnOmG-3Oon6HxoUJDlIrISQ3mPG6yAe7-sp7jCtI5z6zpk5E5p4jxzZgzIn5kTNT7AH7r9I0851l1WA/s1600-h/ckip_client.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 306px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHK6vuFwf29EAQQnlec4pYz2UZXtkuqe2j4CKCsN39LGJiQPFM4Ix4jXAsby2DnOmG-3Oon6HxoUJDlIrISQ3mPG6yAe7-sp7jCtI5z6zpk5E5p4jxzZgzIn5kTNT7AH7r9I0851l1WA/s320/ckip_client.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5325682839067589922" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/CKIP.zip"&gt;Download source code&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/zh-tw/magazine/cc163467.aspx"&gt;實作 CLR 非同步程式撰寫模型 (Programming Model)&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/6821084121963288241/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/04/ckip-client-for-net.html#comment-form" rel="replies" title="12 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6821084121963288241" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6821084121963288241" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/04/ckip-client-for-net.html" rel="alternate" title="CKIP Client for .NET" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKHK6vuFwf29EAQQnlec4pYz2UZXtkuqe2j4CKCsN39LGJiQPFM4Ix4jXAsby2DnOmG-3Oon6HxoUJDlIrISQ3mPG6yAe7-sp7jCtI5z6zpk5E5p4jxzZgzIn5kTNT7AH7r9I0851l1WA/s72-c/ckip_client.png" width="72"/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-4792290650421220155</id><published>2009-03-16T18:09:00.027+08:00</published><updated>2010-07-04T17:27:01.601+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type="text">如何在資料庫存取組合旗標值</title><content type="html">在程式設計當中，如果要建立可以組合列舉值清單的位元旗標列舉型別時，我們會以 2 的乘冪來定義列舉常數。事實上，在資料庫設計中我們也可以沿用位元旗標列舉的概念，使用單一整數型別的欄位來儲存多個整數常值的組合旗標。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;範例資料表&lt;/span&gt;&lt;br /&gt;本文將藉以下是範例資料表來示範如何對數值欄位存取組合旗標：&lt;br /&gt;&lt;pre class="prettyprint"&gt;CREATE TABLE [dbo].[User] ( &lt;br /&gt; [UserName] [varchar] (20) NOT NULL,&lt;br /&gt; [Status] [int] NOT NULL DEFAULT 0&lt;br /&gt;)&lt;/pre&gt;&lt;br /&gt;其中 Status 欄位可以儲存的整數常值以 2 的乘冪定義如下：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th&gt;狀態&lt;/th&gt;&lt;th&gt;整數&lt;/th&gt;&lt;th&gt;二進位值&lt;/th&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td align="left"&gt;APPROVED&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0001&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td align="left"&gt;LOCKED_OUT&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;0010&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td align="left"&gt;BANNED&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;0100&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td align="left"&gt;DELETED&lt;/td&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;1000&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;使用 2 的乘冪來定義整數常值，是為了確保在結合的常數中的個別旗標不會重疊。&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th&gt;DELETED&lt;/th&gt;&lt;th&gt;BANNED&lt;/th&gt;&lt;th&gt;LOCKED_OUT&lt;/th&gt;&lt;th&gt;APPROVED&lt;/th&gt;&lt;th&gt;計算&lt;/th&gt;&lt;th&gt;結果&lt;/th&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1+2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1+4&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;/tr&gt;&lt;tr align="center"&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1+4+8&lt;/td&gt;&lt;td&gt;13&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;加入旗標值&lt;/span&gt;&lt;br /&gt;這時我們所定義的常值便可透過位元 OR 運算來組合旗標值。&lt;br /&gt;&lt;pre class="prettyprint"&gt;INSERT INTO [User] VALUES ('Nancy',1|2)&lt;br /&gt;INSERT INTO [User] VALUES ('Robert',1|4)&lt;br /&gt;INSERT INTO [User] VALUES ('Laura',1|2|4|8)&lt;br /&gt;INSERT INTO [User] VALUES ('Andrew',0)&lt;br /&gt;INSERT INTO [User] VALUES ('Janet',1)&lt;/pre&gt;&lt;br /&gt;當你要測試數值中是否包含特定旗標時，必須先將數值與特定的旗標值進行位元 AND 運算後，再將運算的結果與該旗標值進行相等比較。&lt;br /&gt;&lt;pre class="prettyprint"&gt;SELECT * FROM [User] WHERE Status&amp;2 = 2&lt;/pre&gt;&lt;br /&gt;&lt;table border="0"&gt;&lt;tr&gt;&lt;th&gt;&lt;span style="border-bottom:dashed 1px"&gt;UserName&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span style="border-bottom:dashed 1px"&gt;Status&lt;/span&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nancy&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Laura&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;移除旗標值&lt;/span&gt;&lt;br /&gt;若要在數值中移除特定的旗標值，可以將數值與旗標值進行位元互斥 OR 運算。&lt;br /&gt;&lt;pre class="prettyprint"&gt;UPDATE [User]&lt;br /&gt;SET Status = Status^4&lt;br /&gt;WHERE UserName = 'Robert' AND Status&amp;4 = 4&lt;/pre&gt;&lt;br /&gt;值得注意的是，在對數值與特定的旗標進行位元互斥 OR 運算前，務必先確認該旗標已設定在數值中再執行，否則若貿然對不存在的旗標進行位元互斥 OR 運算將會得到反效果。&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.databasejournal.com/features/mssql/article.php/3359321/Storing-Multiple-Statuses-Using-an-Integer-Column.htm"&gt;Storing Multiple Statuses Using an Integer Column&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.databasejournal.com/features/mssql/article.php/10894_3447811_1/SQL-Server-Updating-Integer-Status-Columns.htm"&gt;SQL Server: Updating Integer Status Columns&lt;/a&gt;&lt;br /&gt;&lt;a href="http://weblogs.asp.net/bdill/archive/2008/01/05/integer-based-bit-manipulation-sql.aspx"&gt;Integer Based Bit Manipulation - SQL&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/4792290650421220155/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/03/storing-multiple-values-in-integer.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4792290650421220155" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/4792290650421220155" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/03/storing-multiple-values-in-integer.html" rel="alternate" title="如何在資料庫存取組合旗標值" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-5253988712673746748</id><published>2009-02-17T09:36:00.022+08:00</published><updated>2010-07-04T16:52:58.704+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><title type="text">實作非同步模式的 TCP 用戶端</title><content type="html">TcpClient 類別是以 Socket 類別為基礎所建立的抽象層 TCP 服務，它提供簡單的方法以連接、傳送和接收網路間的資料，用來簡化 TCP 用戶端應用程式的開發。TcpClient 提供同步與非同步兩種通訊模式，本文將會著重探討如何使用非同步程式撰寫模型來處理網路服務要求。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;同步模式&lt;/span&gt;&lt;br /&gt;在一般的情況下我們都使用同步的封鎖模式來建立 Socket 應用程式，因為這種方式最簡單也最直接。以下範例將會以同步作業的方式發送 HTTP 請求：&lt;br /&gt;&lt;pre class="prettyprint"&gt;using (TcpClient client = new TcpClient("www.msn.com", 80))&lt;br /&gt;{&lt;br /&gt;    using (NetworkStream stream = client.GetStream())&lt;br /&gt;    {&lt;br /&gt;        byte[] send = Encoding.UTF8.GetBytes("GET HTTP/1.0 \r\n\r\n");&lt;br /&gt;        stream.Write(send, 0, send.Length);&lt;br /&gt;        byte[] bytes = new byte[client.ReceiveBufferSize];&lt;br /&gt;        int bytesRead = stream.Read(bytes, 0, (int)client.ReceiveBufferSize);&lt;br /&gt;        String data = Encoding.UTF8.GetString(bytes);&lt;br /&gt;        char[] unused = { (char)data[bytesRead] };&lt;br /&gt;        Console.WriteLine(data.TrimEnd(unused));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;在上例中，我們使用 TcpClient 的建構式進行同步的連接嘗試，並透過 Stream 通訊端同步收發網路資料。在這段時間內，執行同步要求的執行緒會因為等候網路作業完成而無法再執行其他工作。如果該執行緒是 UI 執行緒，那麼應用程式就被封鎖並停止回應使用者的輸入。雖然使用同步封鎖的 Socket 從觀念上來說比較容易使用，然而如果你的應用程式需要保持快速回應、提升延展性及可靠性，那麼就不應該使用同步封鎖的作業方式。&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;非同步模式&lt;/span&gt;&lt;br /&gt;非同步用戶端通訊端使用標準 .NET Framework 非同步程式撰寫模型，讓你的應用程式不會因為等候同步作業完成的執行緒而被封鎖。因為非同步作業（Asynchronous Operation）會在不同的執行緒上（在背景中）執行，所以應用程式可以在呼叫非同步方法（BeginOperationName）的執行緒上繼續執行指令。例如，在 Windows 應用程式中，非同步執行作業將會委派給背景執行緒，而使用者介面執行緒（在前景中）在作業執行時仍可以保持回應狀態。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4cjqcAjRXusZOX5V4PsvbVhjRGg5eSijgoBhyca2IRwOTPw2zuv86O6ENX-AfmW6ltQH0bgUOxEMMqXfr7s-ojCDp6jwq8l5Ypca_mq6UeGCTuJPNrYWbh7dAwhzO6fsdfCghYMZX49o/s1600-h/AsynchronousOperation.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 160px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4cjqcAjRXusZOX5V4PsvbVhjRGg5eSijgoBhyca2IRwOTPw2zuv86O6ENX-AfmW6ltQH0bgUOxEMMqXfr7s-ojCDp6jwq8l5Ypca_mq6UeGCTuJPNrYWbh7dAwhzO6fsdfCghYMZX49o/s320/AsynchronousOperation.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5302658450963934018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;接下來，我們將以 Windows Form 應用程式來逐步建構非同步傳輸的 HTTP 用戶端程式。首先，必須先建立用來在非同步呼叫間傳送狀態資訊的狀態物件。然後，呼叫 TcpClient 物件的 BeginConnect 方法開始遠端主機連接的非同步要求。&lt;br /&gt;&lt;pre class="prettyprint"&gt;TcpClient client = new TcpClient();&lt;br /&gt;StateObject state = new StateObject(client);    &lt;br /&gt;state.Data.AppendFormat("GET {0} HTTP/1.0\r\n", url);&lt;br /&gt;state.Data.AppendFormat("Host:{0}\r\n\r\n", hostName);&lt;br /&gt;&lt;br /&gt;client.BeginConnect(hostName, 0,&lt;br /&gt;       new AsyncCallback(EndConnectCallback), state);&lt;/pre&gt;&lt;br /&gt;當完成非同步連線要求時，系統會回呼實作 AsyncCallback 委派的 EndConnectCallback 方法。在這個方法中，我們必須呼叫 EndConnect 方法來結束擱置的非同步連接要求。下列程式碼實作了 EndConnectCallback 方法：&lt;br /&gt;&lt;pre class="prettyprint"&gt;private void EndConnectCallback(IAsyncResult ar)&lt;br /&gt;{&lt;br /&gt;    StateObject state = (StateObject)ar.AsyncState;&lt;br /&gt;    TcpClient client = state.Client;&lt;br /&gt;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        client.EndConnect(ar);&lt;br /&gt;&lt;br /&gt;        if (client.Connected)&lt;br /&gt;        {&lt;br /&gt;            NetworkStream stream = client.GetStream();&lt;br /&gt;            if (stream.CanWrite)&lt;br /&gt;            {&lt;br /&gt;                byte[] send = Encoding.UTF8.GetBytes(state.Data.ToString());&lt;br /&gt;                stream.BeginWrite(send, 0, send.Length, &lt;br /&gt;                    new AsyncCallback(EndWriteCallback), state);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;            DisplayStatus(string.Format("Ready (last error: {0})", "Connect Failed!"));&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    catch (Exception ex)&lt;br /&gt;    {&lt;br /&gt;        client.Close();&lt;br /&gt;        DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;在用戶端通訊端讀寫資料時，我們需要定義一個能儲存非同步作業相關資訊的狀態物件。&lt;br /&gt;&lt;pre class="prettyprint"&gt;internal class StateObject&lt;br /&gt;{&lt;br /&gt;    public readonly TcpClient Client;&lt;br /&gt;    public readonly byte[] Buffer;&lt;br /&gt;    public readonly StringBuilder Data;&lt;br /&gt;    public readonly int BufferSize = 1024;&lt;br /&gt;&lt;br /&gt;    public StateObject(TcpClient client)&lt;br /&gt;    {&lt;br /&gt;        this.Client = client;&lt;br /&gt;        this.Data = new StringBuilder();&lt;br /&gt;        this.Buffer = new byte[this.BufferSize];&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;當成功連接到遠端主機後，接著會透過 Stream 通訊端的 BeginWrite 方法以非同步方式將 HTTP 請求字串寫入網路資料流，並於作業完成後回呼實作 AsyncCallback 委派的 EndWriteCallback 方法，這個方法會在網路資料流做好接收準備時接收遠端主機回應的資料。&lt;br /&gt;&lt;pre class="prettyprint"&gt;private void EndWriteCallback(IAsyncResult ar)&lt;br /&gt;{&lt;br /&gt;    StateObject state = (StateObject)ar.AsyncState;&lt;br /&gt;    TcpClient client = state.Client;&lt;br /&gt;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        NetworkStream stream = client.GetStream();&lt;br /&gt;        stream.EndWrite(ar);&lt;br /&gt;&lt;br /&gt;        state.Data.Length = 0;&lt;br /&gt;        if (stream.CanRead)&lt;br /&gt;        {&lt;br /&gt;            stream.BeginRead(state.Buffer, 0, state.BufferSize, &lt;br /&gt;                new AsyncCallback(EndReadCallback), state);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    catch (Exception ex)&lt;br /&gt;    {&lt;br /&gt;        client.Close();&lt;br /&gt;        DisplayStatus(string.Format("Ready (last error: {0})", ex.Message));&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;接著會呼叫 Stream 通訊端的 BeginRead 方法，以非同步方式從用戶端通訊端讀取資料，並於作業完成後回呼實作 AsyncCallback 委派的 EndReadCallback 方法，將遠端主機回應的資料讀入資料緩衝區並建立訊息字串。然後再次呼叫 BeginRead 方法，直到用戶端接收資料完畢。&lt;br /&gt;&lt;pre class="prettyprint"&gt;private void EndReadCallback(IAsyncResult ar)&lt;br /&gt;{&lt;br /&gt;    StateObject state = (StateObject)ar.AsyncState;&lt;br /&gt;    TcpClient client = state.Client;&lt;br /&gt;    NetworkStream stream = client.GetStream();&lt;br /&gt;&lt;br /&gt;    int bytesRead = stream.EndRead(ar);&lt;br /&gt;&lt;br /&gt;    if (bytesRead &amp;gt; 0)&lt;br /&gt;    {&lt;br /&gt;        state.Data.Append(Encoding.UTF8.GetString(state.Buffer, 0, bytesRead));&lt;br /&gt;        stream.BeginRead(state.Buffer, 0, state.BufferSize,&lt;br /&gt;            new AsyncCallback(EndReadCallback), state);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        client.Close();&lt;br /&gt;        DisplayResults(state.Data.ToString());&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;最後，呼叫 DisplayResults 方法將非同步讀取作業所建立訊息字串顯示在 TextBox 控制項。&lt;br /&gt;&lt;pre class="prettyprint"&gt;public void DisplayResults(string text)&lt;br /&gt;{&lt;br /&gt;    if (InvokeRequired)&lt;br /&gt;    {&lt;br /&gt;        BeginInvoke(new Action&amp;lt;string&amp;gt;(DisplayResults), text);&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    int hdrLen = 0;&lt;br /&gt;    if (-1 != (hdrLen = text.IndexOf("\r\n\r\n")))&lt;br /&gt;    {&lt;br /&gt;        uxHeader.Text = text.Substring(0, hdrLen);&lt;br /&gt;        char[] unused = { '\r', '\n', '\r', '\n' };&lt;br /&gt;        uxContent.Text = text.Substring(hdrLen).TrimStart(unused);&lt;br /&gt;    }&lt;br /&gt;    else&lt;br /&gt;    {&lt;br /&gt;        uxHeader.Text = string.Empty;&lt;br /&gt;        uxContent.Text = text;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;因為 Windows Form 控制項的存取並沒有保證執行緒安全（Thread-safe），也就是說在當一個以上的執行緒同時存取共用資源時，就會發生競爭情形而導致狀態不一致或是死結的情況。所以，在多執行緒的表單中必須以安全執行緒的方式來存取控制項。因此，在 DisplayResults 方法中使用表單的 InvokeRequired 屬性來判斷呼叫端是否來自於建立控制項之執行緒以外的執行緒。如果是跨執行緒呼叫（Cross-Thread），則必須使用 Invoke 或是 BeginInvoke 方法來封送處理（Marshaling）至控制項的執行緒。當你在 Visual Studio 偵錯工具中執行應用程式，若有不安全的執行緒嘗試存取控制項時，偵錯工具會引發 InvalidOperationException 例外狀況：「跨執行緒作業無效: 存取控制項 &lt;span style="font-style:italic;"&gt;control name&lt;/span&gt; 時所使用的執行緒與建立控制項的執行緒不同」。這也意味只有在偵錯期間才有可能發現這個例外狀況，如果應用程式完成建置與佈署，那麼即使有發生不安全的存取情況也不會引發錯誤，建議你在發現問題時加以修正。&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_9mKTvrnvNrPXAiBCHiuD3sQFgxrtBY7B8N57vWbGMdSSRPqQVb-sORcl1AJgm2astSL6xYfCkpNbQ-TAdFRKByJKOLPLq9_y4ymrA_QrWySIwtA7lk-Hbw9m0VjCa58XEuFKH49qM80/s1600-h/HttpClient.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 304px; height: 320px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_9mKTvrnvNrPXAiBCHiuD3sQFgxrtBY7B8N57vWbGMdSSRPqQVb-sORcl1AJgm2astSL6xYfCkpNbQ-TAdFRKByJKOLPLq9_y4ymrA_QrWySIwtA7lk-Hbw9m0VjCa58XEuFKH49qM80/s320/HttpClient.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5303771638185331458" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/HttpClient.zip"&gt;Download sample code&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx"&gt;Using an Asynchronous Client Socket&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bew39x2a.aspx"&gt;Asynchronous Client Socket Example&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx"&gt;Asynchronous operations, pinning&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/zh-tw/library/2e08f6yc(VS.80).aspx"&gt;以非同步的方式呼叫同步方法&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/zh-tw/library/bbx2eya8(VS.80).aspx"&gt;使用非同步用戶端通訊端&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/5253988712673746748/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/02/asynchronous-tcp-client-using-c.html#comment-form" rel="replies" title="2 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5253988712673746748" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5253988712673746748" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/02/asynchronous-tcp-client-using-c.html" rel="alternate" title="實作非同步模式的 TCP 用戶端" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4cjqcAjRXusZOX5V4PsvbVhjRGg5eSijgoBhyca2IRwOTPw2zuv86O6ENX-AfmW6ltQH0bgUOxEMMqXfr7s-ojCDp6jwq8l5Ypca_mq6UeGCTuJPNrYWbh7dAwhzO6fsdfCghYMZX49o/s72-c/AsynchronousOperation.jpg" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-221420054083454917</id><published>2009-01-13T18:02:00.022+08:00</published><updated>2010-07-04T16:54:11.456+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="iTextSharp"/><title type="text">iTextSharp 中文字型解決方案</title><content type="html">&lt;a href="http://www.1t3xt.com/products/itextsharp.php"&gt;iTextSharp&lt;/a&gt; 是由 iText（for Java）移植到 .NET 平台的開放原始碼專案。它是一個完全使用 C# 語言所撰寫的 PDF APIs，可以讓你即時建立 PDF 文件。然而，當你要使用 iTextSharp 來建立包含中文字型的文件時，就會面臨無法正常顯示中文的問題。這是因為 iTextSharp 只支援 14 個標準的 Type 1 英文字型，並沒有直接支援中文字型的顯示，取而代之的是你必須自行指定中文字型來源才能獲得解決，所以在此整理顯示中文字的幾種解決方案。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Windows 內建的中文字型&lt;/span&gt;&lt;br /&gt;中文版 Windows 內建的中文字型檔可分為 True Type、True Type Collection 及 Open Type 三種字型格式。你可以在 %WINDIR%\Fonts 目錄下找到以 .ttf、.ttc 為延伸檔名的中文字型檔。以下範例將會使用標楷體字型來顯示文字：&lt;br /&gt;&lt;pre class="prettyprint"&gt;Document document = new Document();&lt;br /&gt;PdfWriter.GetInstance(&lt;br /&gt;  document,&lt;br /&gt;  new FileStream(@"cjk.pdf", FileMode.Create)&lt;br /&gt;);&lt;br /&gt;document.Open();&lt;br /&gt;&lt;br /&gt;string fontPath = Environment.GetFolderPath(Environment.SpecialFolder.System) +&lt;br /&gt;    @"\..\Fonts\kaiu.ttf";&lt;br /&gt;BaseFont bfChinese = BaseFont.CreateFont(&lt;br /&gt;    fontPath, &lt;br /&gt;    BaseFont.IDENTITY_H, //橫式中文&lt;br /&gt;    BaseFont.NOT_EMBEDDED&lt;br /&gt;);&lt;br /&gt;Font fontChinese = new Font(bfChinese, 16f, Font.NORMAL);&lt;br /&gt;document.Add(new Paragraph(&lt;br /&gt;    "難得糊塗",&lt;br /&gt;    fontChinese&lt;br /&gt;));&lt;br /&gt;document.Close();&lt;/pre&gt;&lt;br /&gt;在上例中，你也可以使用 FontFactory 代替 BaseFont 來取得中文字型：&lt;br /&gt;&lt;pre class="prettyprint"&gt;FontFactory.Register(fontPath);&lt;br /&gt;Font fontChinese = FontFactory.GetFont("標楷體", BaseFont.IDENTITY_H, 16f);&lt;br /&gt;document.Add(new Paragraph(&lt;br /&gt;    "吃虧是福",&lt;br /&gt;    fontChinese&lt;br /&gt;));&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;CID 字型（Character Identity-keyed Fonts）&lt;/span&gt;&lt;br /&gt;CID 字型格式通常被應用到中日韓（Chinese Japanese Korean, CJK）字元集。如果要使用 CJK 字型，你就必須搭配額外的亞洲語言包 &lt;a href="http://sourceforge.net/project/showfiles.php?group_id=72954&amp;package_id=168416"&gt;iTextAsian-1.0.dll&lt;/a&gt;。&lt;br /&gt;&lt;pre class="prettyprint"&gt;Document document = new Document();&lt;br /&gt;BaseFont.AddToResourceSearch("iTextAsian.dll");&lt;br /&gt;&lt;br /&gt;PdfWriter.GetInstance(&lt;br /&gt;  document,&lt;br /&gt;  new FileStream(@"cjk.pdf", FileMode.Create)&lt;br /&gt;);&lt;br /&gt;document.Open();&lt;br /&gt;&lt;br /&gt;BaseFont bfChinese = BaseFont.CreateFont(&lt;br /&gt;  "MHei-Medium",&lt;br /&gt;  "UniCNS-UCS2-H", // 橫式中文&lt;br /&gt;  BaseFont.NOT_EMBEDDED&lt;br /&gt;);&lt;br /&gt;Font fontChinese = new Font(bfChinese, 8);&lt;br /&gt;document.Add(new Paragraph(&lt;br /&gt;    @"聰明難，糊塗難，&lt;br /&gt;由聰明而轉入糊塗更難，&lt;br /&gt;放一著，退一步，當下心安，非圖後來福報也。",&lt;br /&gt;    fontChinese&lt;br /&gt;));&lt;br /&gt;document.Close();&lt;/pre&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/CJK.zip"&gt;Download sample code&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://itextdocs.lowagie.com/tutorial/fonts/getting/index.php"&gt;iText Tutorial: Getting fonts&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/221420054083454917/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/01/using-chinese-fonts-in-itextsharp.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/221420054083454917" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/221420054083454917" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/01/using-chinese-fonts-in-itextsharp.html" rel="alternate" title="iTextSharp 中文字型解決方案" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s72-c/download.gif" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-142966342986141159</id><published>2009-01-02T16:36:00.025+08:00</published><updated>2010-11-06T21:14:43.218+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="NDde"/><title type="text">Printing PDF Documents using C#</title><content type="html">在報表應用中，PDF 是常被使用的文件格式，透過 &lt;a href="http://itextsharp.sourceforge.net/"&gt;iTextSharp&lt;/a&gt; 可以讓你即時（On-The-Fly）建立 PDF 文件。然而，如果你想自動將建立的文件內容輸出至印表機時，可能就會面臨苦無對策的窘境。因為，iTextSharp 並未提供實際的列印文件功能。所幸，這個問題可以藉由動態資料交換（&lt;a href="http://en.wikipedia.org/wiki/Dynamic_Data_Exchange"&gt;Dynamic Data Exchange, DDE&lt;/a&gt;）技術獲得解決，也就是透過 DDE 從 Adobe Reader 來要求列印指定的文件檔案。在 .NET 中，我們可以使用 &lt;a href="http://www.codeplex.com/ndde"&gt;NDde&lt;/a&gt; 這個開放源碼專案，來輕鬆撰寫 DDE 連結的功能。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;在接下來的程式碼範例中，除了參考「&lt;a href="http://vidmar.net/weblog/archive/2008/04/14/printing-pdf-documents-in-c.aspx"&gt;Printing PDF documents in C#&lt;/a&gt;」的做法外，同時亦採用 Clifton Nock 所著「Data Access Patterns」一書中的 Retryer Pattern。以下程式碼是實作 IRetryable 介面的類別，用來執行列印 PDF 文件的工作：&lt;br /&gt;&lt;pre class="prettyprint"&gt;using System;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;using NDde;&lt;br /&gt;using NDde.Client;&lt;br /&gt;&lt;br /&gt;namespace PdfPrintExample&lt;br /&gt;{&lt;br /&gt;    class PdfPrintOperation : IRetryable&lt;br /&gt;    {        &lt;br /&gt;        private DdeClient _client;&lt;br /&gt;        private string _filePath;&lt;br /&gt;&lt;br /&gt;        public PdfPrintOperation(string filePath)&lt;br /&gt;        {            &lt;br /&gt;            _filePath = filePath;&lt;br /&gt;            _client = new DdeClient("acroview", "control");&lt;br /&gt;        }&lt;br /&gt;       &lt;br /&gt;        public bool Attemp()&lt;br /&gt;        {&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                _client.Connect();&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;            catch (DdeException)&lt;br /&gt;            {        &lt;br /&gt;                // ignore exception        &lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Recover()&lt;br /&gt;        {&lt;br /&gt;            // try running Adobe Reader&lt;br /&gt;            Process p = new Process();&lt;br /&gt;            p.StartInfo.FileName = "AcroRd32.exe";&lt;br /&gt;            p.Start();&lt;br /&gt;            p.WaitForInputIdle();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public void Print()&lt;br /&gt;        {&lt;br /&gt;            _client.Execute("[DocOpen(\"" + _filePath + "\")]", 60000);&lt;br /&gt;            _client.Execute("[FilePrintSilent(\"" + _filePath + "\")]", 60000);&lt;br /&gt;            _client.Execute("[DocClose(\"" + _filePath + "\")]", 60000);&lt;br /&gt;            _client.Execute("[AppExit]", 60000);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;以下是簡單的使用範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;namespace PdfPrintExample&lt;br /&gt;{&lt;br /&gt;    class Program&lt;br /&gt;    {&lt;br /&gt;        static void Main(string[] args)&lt;br /&gt;        {           &lt;br /&gt;            PdfPrintOperation operation = new PdfPrintOperation(@"C:\sample.pdf");&lt;br /&gt;            Retryer retryer = new Retryer(operation);&lt;br /&gt;            retryer.Perform(10, 5000);&lt;br /&gt;            // print the file&lt;br /&gt;            operation.Print();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;使用 Retryer Pattern 的好處在於連結 DDE Server 發生 DDEException 例外狀況時，可以自動嘗試重新連線，直到連接成功或是達到最大重試次數為止。&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/PdfPrintExample.zip"&gt;Download source code&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://vidmar.net/weblog/archive/2008/04/14/printing-pdf-documents-in-c.aspx"&gt;Printing PDF documents in C#&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/142966342986141159/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/01/printing-pdf-documents-using-c.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/142966342986141159" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/142966342986141159" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2009/01/printing-pdf-documents-using-c.html" rel="alternate" title="Printing PDF Documents using C#" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s72-c/download.gif" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-561701341532236771</id><published>2008-12-02T11:14:00.017+08:00</published><updated>2010-07-04T17:10:59.879+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="T-SQL"/><title type="text">Useful User-Defined Functions for SQL Server</title><content type="html">在資料庫設計中，我們常會應用預儲程序（Stored Procedure）來對資料進行 CRUD 操作。除此之外，你也可以撰寫自訂函數來應付經常性的資料存取作業或是複雜的計算等等。在這裡，我羅列幾個我在過去開發商務系統中常會應用到的自訂函數。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;fn_GetNextBusinessDay&lt;/span&gt;&lt;br /&gt;指定起始日期，並傳回最近一個營業日期。&lt;br /&gt;&lt;pre class="prettyprint"&gt;CREATE FUNCTION dbo.fn_GetNextBusinessDay(@StartingDate datetime)&lt;br /&gt;RETURNS datetime&lt;br /&gt;AS  &lt;br /&gt;BEGIN &lt;br /&gt;    DECLARE @NextBusinessDay datetime&lt;br /&gt;&lt;br /&gt;    IF DATEPART(dw, @StartingDate) = (7 - @@DATEFIRST + FLOOR(@@DATEFIRST / 7) * 7) --Saturday&lt;br /&gt;        SET @NextBusinessDay = DATEADD(d, 2, @StartingDate)&lt;br /&gt;    ELSE IF DATEPART(dw, @StartingDate) = (8 - @@DATEFIRST) --Sunday&lt;br /&gt;        SET @NextBusinessDay = DATEADD(d, 1, @StartingDate)&lt;br /&gt;    ELSE&lt;br /&gt;        SET @NextBusinessDay = @StartingDate&lt;br /&gt;&lt;br /&gt;    RETURN @NextBusinessDay&lt;br /&gt;END&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;fn_GetTax&lt;/span&gt;&lt;br /&gt;指定銷售額及稅率，並傳回應付的營業稅額。&lt;br /&gt;&lt;pre class="prettyprint"&gt;CREATE FUNCTION dbo.fn_GetTax(@Amount int, @TaxRate real)&lt;br /&gt;RETURNS real&lt;br /&gt;AS  &lt;br /&gt;BEGIN &lt;br /&gt;    DECLARE @UntaxedPrice int, @Tax int&lt;br /&gt;    SET @UntaxedPrice = ROUND(CAST(@Amount AS real) / (1 + @TaxRate), 0)&lt;br /&gt;    SET @Tax = @Amount - @UntaxedPrice&lt;br /&gt;&lt;br /&gt;    RETURN @Tax&lt;br /&gt;END&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;fn_FormatPercent&lt;/span&gt;&lt;br /&gt;指定浮點數資料，並傳回百分比的表示式。&lt;br /&gt;&lt;pre class="prettyprint"&gt;CREATE FUNCTION dbo.fn_FormatPercent(@InputNumber float)&lt;br /&gt;RETURNS varchar(20)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;     RETURN CAST(CAST(@InputNumber * 100 AS numeric(10, 0)) AS varchar(20)) + '%'&lt;br /&gt;END&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;fn_PadLeft&lt;/span&gt;&lt;br /&gt;將輸入字串靠右對齊，以特定的字元在左側填補至指定的總長度。&lt;br /&gt;&lt;pre class="prettyprint"&gt;CREATE FUNCTION dbo.fn_PadLeft(@InputString varchar(1024), @PaddingChar char(1), @FieldLength int)&lt;br /&gt;RETURNS varchar(1024)&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;    DECLARE @PaddingString varchar(1024)&lt;br /&gt;    IF @FieldLength &amp;gt; 0&lt;br /&gt;        SET @PaddingString = RIGHT(REPLICATE(@PaddingChar, @FieldLength) + @InputString, @FieldLength)&lt;br /&gt;    ELSE&lt;br /&gt;        SET @PaddingString = @InputString&lt;br /&gt;&lt;br /&gt;   RETURN @PaddingString&lt;br /&gt;END&lt;/pre&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/561701341532236771/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/12/useful-user-defined-functions.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/561701341532236771" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/561701341532236771" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/12/useful-user-defined-functions.html" rel="alternate" title="Useful User-Defined Functions for SQL Server" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-8200037304582546170</id><published>2008-11-15T15:42:00.027+08:00</published><updated>2010-07-04T17:04:45.037+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="LINQ"/><title type="text">Read Fixed-Width Text Records using C#</title><content type="html">雖然使用純文字檔格式（Flat File）來交換資料並不是很好的方式，然而在 XML 盛行的今日它仍是普遍存在的資料交換格式。純文字檔格式的資料列通常以特定的符號區隔，或是固定寬度欄位來區隔不同資料欄位。從程式員的觀點來看，處理固定寬度欄位格式的資料並不如使用特定的符號區隔的格式來得輕鬆。如果是使用傳統的方式從「位置」擷取資料，那將會更加麻煩。所以，本文在這裡就要介紹幾種處理固定寬度格式資料的解決方案。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;以下範例文字檔內容是以固定寬度格式所描述的銷售訂單內容：&lt;br /&gt;&lt;pre&gt;0001S0000120081101       2     5000&lt;br /&gt;0001S0000220081101      10     2500&lt;br /&gt;0001S0000320081101       1    10500&lt;/pre&gt;&lt;br /&gt;其檔案格式內容定義如下：&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;欄位名稱&lt;/th&gt;&lt;th&gt;欄位長度&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;銷售店代號&lt;/td&gt;&lt;td&gt;X(4)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;訂單編號&lt;/td&gt;&lt;td&gt;X(6)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;訂單日期&lt;/td&gt;&lt;td&gt;X(8)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;銷售量&lt;/td&gt;&lt;td&gt;9(8)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;銷售金額&lt;/td&gt;&lt;td&gt;9(9)&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;LINQ to Text Files&lt;/span&gt;&lt;br /&gt;首先必須先定義一個延伸方法（Extension Method）來逐行讀取資料流，並建立可以供 LINQ 查詢的可列舉集合。在此我引用了 Eric White 在 &lt;a href="http://blogs.msdn.com/ericwhite/archive/2006/08/31/734383.aspx"&gt;LINQ to Text Files&lt;/a&gt; 中所提供的 StreamReaderSequence 類別：&lt;br /&gt;&lt;pre class="prettyprint"&gt;public static class StreamReaderSequence&lt;br /&gt;{&lt;br /&gt;    public static IEnumerable&amp;lt;string&amp;gt; Lines(this StreamReader source)&lt;br /&gt;    {&lt;br /&gt;        String line;&lt;br /&gt;&lt;br /&gt;        if (source == null)&lt;br /&gt;            throw new ArgumentNullException("source");&lt;br /&gt;        while ((line = source.ReadLine()) != null)&lt;br /&gt;        {&lt;br /&gt;            yield return line;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;接下來使用規則運算式（Regular expression）依序定義群組編號及資料欄位長度：&lt;br /&gt;&lt;pre class="prettyprint"&gt;Regex re = new Regex("^(?&amp;lt;1&amp;gt;.{4})" +&lt;br /&gt;                    "(?&amp;lt;2&amp;gt;.{6})" +&lt;br /&gt;                    "(?&amp;lt;3&amp;gt;.{8})" +&lt;br /&gt;                    "(?&amp;lt;4&amp;gt;.{8})" +&lt;br /&gt;                    "(?&amp;lt;5&amp;gt;.{9})", &lt;br /&gt;                    RegexOptions.Compiled);&lt;/pre&gt;&lt;br /&gt;接著再搭配 LINQ 語法的 let 子句取得規則運算式比對所擷取的群組集合，然後併入查詢結果中：&lt;br /&gt;&lt;pre class="prettyprint"&gt;using (StreamReader sr = new StreamReader(@"d:\orders.txt"))&lt;br /&gt;{                                &lt;br /&gt;    var orders = &lt;br /&gt;        from line in sr.Lines()&lt;br /&gt;        let fields = re.Match(line).Groups&lt;br /&gt;        select new&lt;br /&gt;        {&lt;br /&gt;            StoreID = fields[1].Value.Trim(),&lt;br /&gt;            OrderNumber = fields[2].Value.Trim(),&lt;br /&gt;            OrderDate = DateTime.ParseExact(fields[3].Value.Trim(), &lt;br /&gt;                            "yyyyMMdd", CultureInfo.InvariantCulture),&lt;br /&gt;            Quantity = int.Parse(fields[4].Value),&lt;br /&gt;            Amount = int.Parse(fields[5].Value)&lt;br /&gt;        };&lt;br /&gt;  &lt;br /&gt;    foreach (var order in orders)&lt;br /&gt;    {&lt;br /&gt;        Console.WriteLine("{0},{1},{2},{3},{4}",&lt;br /&gt;            order.StoreID,&lt;br /&gt;            order.OrderNumber,&lt;br /&gt;            order.OrderDate,&lt;br /&gt;            order.Quantity,&lt;br /&gt;            order.Amount&lt;br /&gt;        );     &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;LINQ to SQL&lt;/span&gt;&lt;br /&gt;Microsoft OLE DB Provider for Jet 可用來存取及查詢文字檔，但必須在文字檔的相同目錄中建立 &lt;a href="http://msdn.microsoft.com/en-us/library/ms709353.aspx"&gt;Schema.ini&lt;/a&gt; 檔來描述文字檔的結構：&lt;br /&gt;&lt;pre&gt;[orders.txt]&lt;br /&gt;Format=FixedLength&lt;br /&gt;ColNameHeader=False&lt;br /&gt;MaxScanRows=0&lt;br /&gt;Col1=StoreID Text Width 4&lt;br /&gt;Col2=OrderNumber Text Width 6&lt;br /&gt;Col3=OrderDate DateTime Width 8&lt;br /&gt;Col4=Quantity Long Width 8&lt;br /&gt;Col5=Amount Long Width 9&lt;br /&gt;DateTimeFormat=yyyyMMdd&lt;/pre&gt;&lt;br /&gt;然後，再定義一個資料結構對應的類別：&lt;br /&gt;&lt;pre class="prettyprint"&gt;public class Order&lt;br /&gt;{&lt;br /&gt;    public string StoreID;&lt;br /&gt;    public string OrderNumber;&lt;br /&gt;    public DateTime OrderDate;&lt;br /&gt;    public int Quantity;&lt;br /&gt;    public int Amount;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;使用 DataContext 物件透過資料庫連接直接執行 SQL 查詢，並傳回資料結構對應的物件集合。&lt;br /&gt;&lt;pre class="prettyprint"&gt;string filePath = @"d:\orders.txt";&lt;br /&gt;string connString = string.Format( @"Provider=Microsoft.Jet.OLEDB.4.0;" +&lt;br /&gt;                    "Data Source={0};" +&lt;br /&gt;                    "Extended Properties='text;HDR=No;Format=FixedLength'",&lt;br /&gt;                    Path.GetDirectoryName(filePath));&lt;br /&gt;&lt;br /&gt;OleDbConnection conn = new OleDbConnection(connString);&lt;br /&gt;DataContext db = new DataContext(conn);&lt;br /&gt;&lt;br /&gt;string cmdText = string.Format("SELECT * FROM {0}", &lt;br /&gt;                Path.GetFileName(filePath).Replace(".", "#"));&lt;br /&gt;var orders = db.ExecuteQuery&amp;lt;Order&amp;gt;(cmdText);&lt;br /&gt;&lt;br /&gt;foreach (var order in orders)&lt;br /&gt;{                &lt;br /&gt;    Console.WriteLine("{0},{1},{2},{3},{4}",&lt;br /&gt;        order.StoreID,&lt;br /&gt;        order.OrderNumber,&lt;br /&gt;        order.OrderDate,&lt;br /&gt;        order.Quantity,&lt;br /&gt;        order.Amount&lt;br /&gt;    );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;FileHelpers Library&lt;/span&gt;&lt;br /&gt;&lt;a href="http://filehelpers.sourceforge.net/"&gt;FileHelpers&lt;/a&gt; 是一個用來處理符號區隔或是固定寬度資料的免費類別庫。使用前，你首先必須先定義一個資料結構對應的類別：&lt;br /&gt;&lt;pre class="prettyprint"&gt;[FixedLengthRecord]&lt;br /&gt;public class Order&lt;br /&gt;{&lt;br /&gt;    [FieldFixedLength(4)]        &lt;br /&gt;    public string StoreID;&lt;br /&gt;&lt;br /&gt;    [FieldFixedLength(6)]        &lt;br /&gt;    public string OrderNumber;&lt;br /&gt;&lt;br /&gt;    [FieldFixedLength(8)]        &lt;br /&gt;    [FieldConverter(ConverterKind.Date, "yyyyMMdd")]&lt;br /&gt;    public DateTime OrderDate;&lt;br /&gt;  &lt;br /&gt;    [FieldFixedLength(8)]&lt;br /&gt;    [FieldTrim(TrimMode.Left)]&lt;br /&gt;    public int Quantity;&lt;br /&gt;&lt;br /&gt;    [FieldFixedLength(9)]&lt;br /&gt;    [FieldTrim(TrimMode.Left)]&lt;br /&gt;    public int Amount;&lt;br /&gt;} &lt;/pre&gt;&lt;br /&gt;然後，透過 FileHelperEngine 讀取資料檔就會自動建立對應的物件陣列。&lt;br /&gt;&lt;pre class="prettyprint"&gt;FileHelperEngine engine = new FileHelperEngine(typeof(Order));          &lt;br /&gt;Order[] orders = engine.ReadFile(@"d:\orders.txt") as Order[];&lt;br /&gt;&lt;br /&gt;foreach (var order in orders)&lt;br /&gt;{&lt;br /&gt;    Console.WriteLine("{0},{1},{2},{3},{4}",&lt;br /&gt;        order.StoreID,&lt;br /&gt;        order.OrderNumber,&lt;br /&gt;        order.OrderDate,&lt;br /&gt;        order.Quantity,&lt;br /&gt;        order.Amount&lt;br /&gt;    );&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://blogs.msdn.com/ericwhite/archive/2006/08/31/734383.aspx"&gt;LINQ TO Text Files&lt;/a&gt; by Eric White&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/8200037304582546170/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/read-fixed-width-text-records-using-c.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8200037304582546170" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8200037304582546170" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/read-fixed-width-text-records-using-c.html" rel="alternate" title="Read Fixed-Width Text Records using C#" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-8885818252811349441</id><published>2008-11-11T11:09:00.028+08:00</published><updated>2009-06-19T09:20:36.359+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><title type="text">使用 C# 產生網頁縮圖</title><content type="html">在 Web 2.0 網站中，我們常可以看到分享文章或是推薦網站的快照縮圖（Snapshot Thumbnail），來供使用者預覽。如果要在 .NET 中要實做網頁快照，你可以使用 WebBrowser 控制項來達成。在本文中將會示範如何建立 Windows 應用程式來擷取網頁快照並產生縮圖。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj05KJAnN4U3mowYcAEC1XQ5rJX_SeUcGnN_yu-tNRrY0bxy2oTFT8F4mdqE9ttU_jl53QmRJsecigrSQNzKxL3SO_SAHk6uyxWCQ8OKfHMhYMTW-4zEOUcbEIYa6EH-IG3HAaq2OB_xh0/s1600-h/snap.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 273px; height: 238px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj05KJAnN4U3mowYcAEC1XQ5rJX_SeUcGnN_yu-tNRrY0bxy2oTFT8F4mdqE9ttU_jl53QmRJsecigrSQNzKxL3SO_SAHk6uyxWCQ8OKfHMhYMTW-4zEOUcbEIYa6EH-IG3HAaq2OB_xh0/s320/snap.png" border="0" alt="snap" id="BLOGGER_PHOTO_ID_5268361873023623522" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;範例程式碼&lt;/span&gt;&lt;pre&gt;using System;&lt;br /&gt;using System.Drawing;&lt;br /&gt;using System.Drawing.Drawing2D;&lt;br /&gt;using System.Windows.Forms;&lt;br /&gt;&lt;br /&gt;namespace SnapExample&lt;br /&gt;{&lt;br /&gt;    public partial class MainForm : Form&lt;br /&gt;    {&lt;br /&gt;        private WebPageSnapshot _wps = new WebPageSnapshot(1024, 768);&lt;br /&gt;&lt;br /&gt;        public MainForm()&lt;br /&gt;        {&lt;br /&gt;            InitializeComponent();            &lt;br /&gt;            _wps.ImageCompleted += new ImageCompletedEventHandler(RefreshImage);&lt;br /&gt;        }&lt;br /&gt;                               &lt;br /&gt;        private void uxGo_Click(object sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            EnableButtons(false);&lt;br /&gt;            _wps.GenerateAsync(uxUrl.Text);                        &lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void uxSaveAs_Click(object sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            uxSaveFileDialog.DefaultExt = "jpg";&lt;br /&gt;            uxSaveFileDialog.AddExtension = true;&lt;br /&gt;            uxSaveFileDialog.Filter = "JPEG(*.jpg)|*.jpg";&lt;br /&gt;            uxSaveFileDialog.ShowDialog(this);&lt;br /&gt;&lt;br /&gt;            string fileName = uxSaveFileDialog.FileName;&lt;br /&gt;            if (fileName != string.Empty)&lt;br /&gt;            {&lt;br /&gt;                uxThumbnail.BackgroundImage.Save(fileName);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void RefreshImage(Image image)&lt;br /&gt;        {                        &lt;br /&gt;            decimal sizeRatio = ((decimal)image.Height / image.Width);&lt;br /&gt;&lt;br /&gt;            int thumbWidth = 100;&lt;br /&gt;            int thumbHeight = decimal.ToInt32(sizeRatio * thumbWidth);&lt;br /&gt;            &lt;br /&gt;            Image thumb = image.GetThumbnailImage(&lt;br /&gt;                thumbWidth, thumbHeight,&lt;br /&gt;                () =&amp;gt; false,&lt;br /&gt;                IntPtr.Zero&lt;br /&gt;            );&lt;br /&gt;                      &lt;br /&gt;            if (WebPageSnapshot.IsBlank((Bitmap)thumb))&lt;br /&gt;            {&lt;br /&gt;                using (Graphics g = Graphics.FromImage(thumb))&lt;br /&gt;                {&lt;br /&gt;                    StringFormat format = new StringFormat();                    &lt;br /&gt;                    format.Alignment = StringAlignment.Center;&lt;br /&gt;                    format.LineAlignment = StringAlignment.Center;&lt;br /&gt;                    g.DrawString(&lt;br /&gt;                        "IMAGE NOT AVAILABLE", &lt;br /&gt;                        new Font("Tahoma", 65), &lt;br /&gt;                        Brushes.DarkGray,&lt;br /&gt;                        new RectangleF(0, 0, thumbWidth, thumbHeight), &lt;br /&gt;                        format&lt;br /&gt;                        );             &lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            uxThumbnail.BackgroundImage = thumb;           &lt;br /&gt;                                   &lt;br /&gt;            EnableButtons(true);&lt;br /&gt;        }&lt;br /&gt;                &lt;br /&gt;        private void EnableButtons(bool enabled)&lt;br /&gt;        {&lt;br /&gt;            uxSaveAs.Enabled = enabled;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        private void uxCancel_Click(object sender, EventArgs e)&lt;br /&gt;        {&lt;br /&gt;            _wps.CancelAsync();&lt;br /&gt;        }               &lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;WebPageSnapshot 是一個以 WebBrowse 類別為對象的自訂外覆類別（Wrapper Class）。透過非同步呼叫 GenerateAsync 方法，會將網頁載入到內部隱含的 WebBrowser 實例中。當 WebBrowser 完整載入網頁後，便會呼叫其 DrawToBitmap 方法建立網頁快照的點陣圖，然後引發 ImageCompleted 事件傳回快照圖。在上例中，將會由 RefreshImage 程序來處理 ImageCompleted 事件，並藉由傳入的 Image 物件的 GetThumbnailImage 方法建立縮圖影像。&lt;br /&gt;&lt;br /&gt;不過，在測試過程中發現偶會有擷取到空白影像的情況。為了能處理此例外狀況，我從&lt;a href="http://www.chinhdo.com/20080910/detect-blank-images/"&gt;這裡&lt;/a&gt;找來了辨識空白圖片的程式演算法，並引用到 WebPageSnapshot 類別的 IsBlank 靜態方法。在範例中，我就對空白截圖繪製了 "IMAGE NOT AVAILABLE" 的字樣。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDegPRurUCrNjHgzsz4JIP8k0YzA05OxYsw8-Ku5ffocMjWparl7t9or3TBu1dPP5BW1DGo_0jsV-gvm30DMpWbS461flWpFXEL3vqgwAgPOr15vVqGuy4STk7XwX4xZyZJdpijdn9e4w/s1600-h/no_image.jpg"&gt;&lt;img style="cursor:pointer;cursor:hand;width:100px; height:75px;border-color:#000000;border-style:dotted;border-width:1px" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDegPRurUCrNjHgzsz4JIP8k0YzA05OxYsw8-Ku5ffocMjWparl7t9or3TBu1dPP5BW1DGo_0jsV-gvm30DMpWbS461flWpFXEL3vqgwAgPOr15vVqGuy4STk7XwX4xZyZJdpijdn9e4w/s320/no_image.jpg" alt="no image" id="BLOGGER_PHOTO_ID_5268344859507436466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/SnapExample.zip"&gt;Download source code&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.chinhdo.com/20080910/detect-blank-images/"&gt;Algorithm to Detect Blank Images&lt;/a&gt; by Chinh Do&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/wewwczdw.aspx"&gt;Event-based Asynchronous Pattern Overview&lt;/a&gt; by Microsoft&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/8885818252811349441/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/generate-webpage-thumbnail-using-c.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8885818252811349441" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/8885818252811349441" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/generate-webpage-thumbnail-using-c.html" rel="alternate" title="使用 C# 產生網頁縮圖" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj05KJAnN4U3mowYcAEC1XQ5rJX_SeUcGnN_yu-tNRrY0bxy2oTFT8F4mdqE9ttU_jl53QmRJsecigrSQNzKxL3SO_SAHk6uyxWCQ8OKfHMhYMTW-4zEOUcbEIYa6EH-IG3HAaq2OB_xh0/s72-c/snap.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-651765286507312670</id><published>2008-11-07T10:38:00.020+08:00</published><updated>2010-07-04T17:02:05.302+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type="text">ASP.NET Image Uploading with Resizing</title><content type="html">當你使用 ASP.NET 建立上傳圖檔的應用程式時，除了要決定寫入檔案系統或是儲存到資料庫外，你可能還會需要依照原圖的尺寸比例來調整圖片的大小，以符合系統的需求。本文範例程式碼將透過 Image 及 Bitmap 類別，對上傳的原圖進行比例縮放，並以 JPEG 圖檔格式存儲。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;%@ Page Language="C#" %&amp;gt;&lt;br /&gt;&amp;lt;%@ Import Namespace="System.IO" %&amp;gt;&lt;br /&gt;&amp;lt;%@ Import Namespace="Drawing=System.Drawing" %&amp;gt;&lt;br /&gt;&amp;lt;script runat="server"&amp;gt;    &lt;br /&gt;    const string _uploadFolder = "~/images/";&lt;br /&gt;    const int _maxThumbWidth = 100;&lt;br /&gt;&lt;br /&gt;    protected void uxUpload_Click(object sender, EventArgs e)&lt;br /&gt;    {&lt;br /&gt;        if (uxImageFile.HasFile)&lt;br /&gt;        {&lt;br /&gt;            if (IsValidImage(uxImageFile.FileName))&lt;br /&gt;            {&lt;br /&gt;                string thumbPath = _uploadFolder + &lt;br /&gt;                    Path.ChangeExtension(Path.GetRandomFileName(), ".jpg");&lt;br /&gt;                            &lt;br /&gt;                using (Drawing::Image image = &lt;br /&gt;                    Drawing::Image.FromStream(uxImageFile.PostedFile.InputStream))&lt;br /&gt;                {&lt;br /&gt;                    decimal sizeRatio = ((decimal)image.Height / image.Width);&lt;br /&gt;                    int thumbWidth = _maxThumbWidth;&lt;br /&gt;                    int thumbHeight = decimal.ToInt32(sizeRatio * thumbWidth);&lt;br /&gt;&lt;br /&gt;                    using (Drawing::Bitmap bitmap = &lt;br /&gt;                        new Drawing::Bitmap(image, new Drawing::Size(thumbWidth, thumbHeight)))&lt;br /&gt;                    {&lt;br /&gt;                        bitmap.Save(Server.MapPath(thumbPath), &lt;br /&gt;                           Drawing::Imaging.ImageFormat.Jpeg);&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;                uxThumbImage.ImageUrl = thumbPath;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                // This type of file is not allowed.&lt;br /&gt;                uxThumbImage.ImageUrl = string.Empty;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public bool IsValidImage(string path)&lt;br /&gt;    {&lt;br /&gt;        return Regex.IsMatch(path, @"(.*?)\.(gif|jpg|jpeg|png)$", RegexOptions.IgnoreCase);&lt;br /&gt;    }&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &lt;br /&gt;    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml"&amp;gt;&lt;br /&gt;&amp;lt;head runat="server"&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Image Upload and Resize&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;form id="form1" runat="server"&amp;gt;&lt;br /&gt;        &amp;lt;div&amp;gt;&lt;br /&gt;            &amp;lt;asp:FileUpload ID="uxImageFile" runat="server" /&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;            &amp;lt;asp:Button ID="uxUpload" runat="server"&lt;br /&gt;                Text="Upload" onclick="uxUpload_Click" /&amp;gt;&amp;lt;br/&amp;gt;&lt;br /&gt;            &amp;lt;asp:Image ID="uxThumbImage" runat="server" &lt;br /&gt;                onerror="javascript:this.style.display='none';" /&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/form&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.cosmocentral.com/post/Create-High-Quality-Thumbnail---Resize-Image-Dynamically---ASP-Net-C-Code.aspx"&gt;Create High Quality Thumbnail - Resize Image Dynamically - ASP .Net C# Code&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/651765286507312670/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/aspnet-image-uploading-with-resizing.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/651765286507312670" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/651765286507312670" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/11/aspnet-image-uploading-with-resizing.html" rel="alternate" title="ASP.NET Image Uploading with Resizing" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-3508401826597142363</id><published>2008-10-27T16:16:00.021+08:00</published><updated>2008-10-29T10:52:52.215+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="CSS"/><title type="text">Understanding CSS Positioning</title><content type="html">在網頁中，CSS 將每個元素視為一個矩形區塊（Box）。每個區塊則由內容（Content）、邊距（Padding）、邊框（Border）及邊界（Margin）等區域組合而成，這樣的概念又被稱為區塊模型（Box Model）。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKoz5GhH9b1s88Y3w5t5NA4drqMpH0jFFRZW5lfkUm8BnROGDhEQo9VyJa_JBcg3U0BhvD86F2u3E_c3JlCd5nYcdOLApUTyl3YrFG29bKIqn93R2EYq7DxBmM-sVPguZZ71UCIpr7_1s/s1600-h/box.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 256px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKoz5GhH9b1s88Y3w5t5NA4drqMpH0jFFRZW5lfkUm8BnROGDhEQo9VyJa_JBcg3U0BhvD86F2u3E_c3JlCd5nYcdOLApUTyl3YrFG29bKIqn93R2EYq7DxBmM-sVPguZZ71UCIpr7_1s/s320/box.png" border="0" alt="box" id="BLOGGER_PHOTO_ID_5261830151355906178" /&gt;&lt;/a&gt;&lt;br /&gt;CSS 運用區塊模型的概念，將樣式套用在元素上來決定其外觀及位置。本文接下來將介紹在 CSS 排版中不可或缺的定位（Positioning）觀念。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;strong&gt;靜態位置（position:static）&lt;/strong&gt;&lt;br /&gt;這是所有 HTML 元素預設的 position 屬性值（也就是沒有定位），它會配合版面配置規則（Layout Rule）決定其位置座標。所以，如果在 position:static 的元素設定 top、left、right 或 bottom 等偏移（Offset）屬性將會自動被忽略。&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;相對位置（position:relative）&lt;/strong&gt;&lt;br /&gt;相對於原本的位置（靜態位置），也就是將元素從原先的位置，依據元素的偏移屬性，將元素作對應的距離調整，而且其原本位置的區塊空間將會被保留，位移後也可能會覆蓋其它區塊。如果有區塊相互重疊的情況，你可以使用 z-index 屬性來決定重疊的順序。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin-yeZ8bGtq1B6RKMNEsmfnLBsCagurfvwy1njoJN3pzvsG4mSLgUsNR2VE3KQzg4LjZl5KiUJ6WyVmbMHRaoH4RArPsGUzV3L39lJdMJYqkESZdsjmRUXDi6ktQg0Netji9540vqjyqo/s1600-h/relative.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 248px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEin-yeZ8bGtq1B6RKMNEsmfnLBsCagurfvwy1njoJN3pzvsG4mSLgUsNR2VE3KQzg4LjZl5KiUJ6WyVmbMHRaoH4RArPsGUzV3L39lJdMJYqkESZdsjmRUXDi6ktQg0Netji9540vqjyqo/s320/relative.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5262090173829702306" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;絕對位置（position:absolute）&lt;/strong&gt;&lt;br /&gt;以父元素的邊界位置為基點，再依據偏移屬性作對應的距離調整。如果其上層的親代元素都不是以 absolute 或 relative 定位時，那麼就會以 body 元素的邊界為基準。該元素會從 HTML 的正常排版（Normal Flow）中移除，然後再依據容器區塊（Containing Box）的邊界來重新定位該元素，因此也可能會覆蓋其它原塊。而所謂的正常排版是指從上而下、由左至右的編排方式。例如段落區塊（Block Box）會在其容器區塊中從上而下排列；而行內區塊（Inline Box）則是由左至右排列。&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaXBPzMFgXvxAL_51QZqhyphenhyphenjZZXawC_SB7r7gRQmWgWVDS-bG8tC-7UPhGg_Vs4punqKmNyKNbVSGEULgxRhvXSRXLIAc0-qpbXcV_JuuFyPojJ5WVHCKZe-iY2CL2iwEj7FruDLsUIuak/s1600-h/absolute.png"&gt;&lt;img style="cursor:pointer; cursor:hand;width: 320px; height: 243px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaXBPzMFgXvxAL_51QZqhyphenhyphenjZZXawC_SB7r7gRQmWgWVDS-bG8tC-7UPhGg_Vs4punqKmNyKNbVSGEULgxRhvXSRXLIAc0-qpbXcV_JuuFyPojJ5WVHCKZe-iY2CL2iwEj7FruDLsUIuak/s320/absolute.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5262117535729105042" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;固定位置（position:fixed）&lt;/strong&gt;&lt;br /&gt;基本上與絕對位置的定位方式相同，為一的差別在於其位置固定，且不會隨捲軸的移動而改變，就像浮水印（Watermark）一樣。這個屬性值並不適用 IE 6 或更早期的版本。&lt;br /&gt;&lt;br /&gt;參考資料：&lt;br /&gt;&lt;a href="http://www.w3.org/TR/css3-box/"&gt;CSS basic box model&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/3508401826597142363/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/understanding-css-positioning.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/3508401826597142363" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/3508401826597142363" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/understanding-css-positioning.html" rel="alternate" title="Understanding CSS Positioning" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKoz5GhH9b1s88Y3w5t5NA4drqMpH0jFFRZW5lfkUm8BnROGDhEQo9VyJa_JBcg3U0BhvD86F2u3E_c3JlCd5nYcdOLApUTyl3YrFG29bKIqn93R2EYq7DxBmM-sVPguZZ71UCIpr7_1s/s72-c/box.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-6955063948845090512</id><published>2008-10-14T14:09:00.017+08:00</published><updated>2008-10-17T11:48:14.599+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Best Practices"/><title type="text">.NET Naming Conventions</title><content type="html">遵循良好的命名慣例可以讓程式更容易被理解和閱讀。尤其，在團隊工作中採用一致的命名方針將利於程式碼的整合與維護。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://zh.wikipedia.org/wiki/匈牙利命名法"&gt;匈牙利命名法&lt;/a&gt;（Hungarian Notation）是常見的命名方式，如果你在 .NET 程式設計中一眛的沿用匈牙利命名法，不僅無助於提升程式碼的可維護性，甚至會因為命名冗雜造成反效果。果真如此，你就更應該考慮使用更好的命名方式。在這裡推薦由 Pete Brown 依據微軟的&lt;a href="http://msdn.microsoft.com/zh-tw/library/ms229042(VS.80).aspx"&gt;開發類別庫的設計方針&lt;/a&gt;及業界公認標準（Industry-Accepted Standards）所整理的&lt;a href="http://www.irritatedvowel.com/Programming/Standards.aspx"&gt; .NET 命名準則&lt;/a&gt;，非常具有參考價值。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;值得一提的是，這份文件還特別針對 Windows 表單和 Web 表單中的 UI 控制項識別名稱，提出獨道的命名原則。雖然作者特別強調不贊成使用匈牙利命名法的原因，然而在不使用匈牙利命名法的原則下，UI 控制項的識別名稱是唯一不在此限的例外。作者建議對所有 UI 控制項的識別名稱，統一採用 "ux"（意即 &lt;strong&gt;U&lt;/strong&gt;ser e&lt;strong&gt;X&lt;/strong&gt;perience 的縮寫）做為前綴詞（Prefix），其所持的理由如下：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;相較於使用型別相依的匈牙利命名法更為簡潔，且不用顧慮變更控制項型別所帶來的名稱衝突問題。&lt;/li&gt;&lt;li&gt;有助於在 Intellisense 中將你的控制項型別變數名稱群組在一起。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;如此一來，將可擺脫以往使用繁雜的控制項前綴詞（如 txt、btn 等）的命名方式。如果你也像我一樣常為控制項識別名稱命名感到苦惱，那麼相信採用新命名法將會為你帶來更佳的表單開發經驗。&lt;br /&gt;&lt;br /&gt;資料來源：&lt;br /&gt;&lt;a href="http://www.irritatedvowel.com/Programming/Standards.aspx"&gt;Common .NET Naming Conventions&lt;/a&gt; by Pete Brown&lt;br /&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/6955063948845090512/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/net-naming-conventions.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6955063948845090512" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/6955063948845090512" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/net-naming-conventions.html" rel="alternate" title=".NET Naming Conventions" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-5921718512901059788</id><published>2008-10-13T15:09:00.022+08:00</published><updated>2010-07-04T21:12:08.994+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="JavaScript"/><category scheme="http://www.blogger.com/atom/ns#" term="MooTools"/><title type="text">Mooquee - Marquee with Mootools</title><content type="html">&lt;a href="http://robertinglin.com/mooquee/"&gt;Mooquee&lt;/a&gt; 是一個以 MooTools 為基礎所設計的跑馬燈的 JavaScript 類別，它提供建構選項可以表現出多種不同於 Marquee 標籤的跑馬燈動畫效果。&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;實作時，除了要引用 Mooquee 程式庫外，你還需要搭配 &lt;a href="http://mootools.net/download"&gt;MooTools 1.2&lt;/a&gt;。在建構 Mooquee 物件時，你可以設定以下建構選項：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;element：指定做為跑馬燈區塊的 HTML 元素識別碼。&lt;/li&gt;&lt;li&gt;cssitem：指定播放項目的樣式類別名稱。&lt;/li&gt;&lt;li&gt;firstitem：指定第一個播放項目的索引。&lt;/li&gt;&lt;li&gt;direction：以 up、down、left 或 right 指定跑馬燈移動的方向。&lt;/li&gt;&lt;li&gt;pause：以秒為單位指定每次停止時間，且必須大於或等於 duration 的值，其預設值為 1 秒。&lt;/li&gt;&lt;li&gt;duration：以秒為單位指定每次移動所需時間，其預設值為 1 秒。&lt;/li&gt;&lt;li&gt;overflow：設定當內容超出跑馬燈區塊範圍時的處理方式，預設值為 hidden。&lt;/li&gt;&lt;li&gt;startOnLoad：指定是否自動播放，預設值為 true。&lt;/li&gt;&lt;/ul&gt;如以下範例會建立向上垂直捲動的跑馬燈：&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" &lt;br /&gt;    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&amp;gt;&lt;br /&gt;&amp;lt;html xmlns="http://www.w3.org/1999/xhtml" &amp;gt;&lt;br /&gt;&amp;lt;head&amp;gt;&lt;br /&gt;    &amp;lt;title&amp;gt;Mooquee Example&amp;lt;/title&amp;gt;&lt;br /&gt;    &amp;lt;style type="text/css"&amp;gt;&lt;br /&gt;        #mooquee_container {&lt;br /&gt;            width: 200px;&lt;br /&gt;            height: 20px;&lt;br /&gt;            border: 1px solid;&lt;br /&gt;        }&lt;br /&gt;        .mooquee_item { &lt;br /&gt;            background-color: #ffffff; &lt;br /&gt;        }&lt;br /&gt;    &amp;lt;/style&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript" src="mootools-1.2-core.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;    &amp;lt;script type="text/javascript" src="Mooquee.js"&amp;gt;&amp;lt;/script&amp;gt;   &lt;br /&gt;    &amp;lt;script type="text/javascript"&amp;gt;&lt;br /&gt;        window.addEvent('domready', function() {&lt;br /&gt;            var mooquee = new Mooquee({&lt;br /&gt;                element:'mooquee_container',     &lt;br /&gt;                cssitem:'mooquee_item',&lt;br /&gt;                direction:'up',&lt;br /&gt;                duration:1,&lt;br /&gt;                pause:2,&lt;br /&gt;                firstitem:0&lt;br /&gt;            });&lt;br /&gt;        });&lt;br /&gt;    &amp;lt;/script&amp;gt;&lt;br /&gt;&amp;lt;/head&amp;gt;&lt;br /&gt;&amp;lt;body&amp;gt;&lt;br /&gt;    &amp;lt;div id="mooquee_container"&amp;gt; &lt;br /&gt;     &amp;lt;div class="mooquee_item"&amp;gt;跑馬燈訊息第 1 則&amp;lt;/div&amp;gt; &lt;br /&gt;     &amp;lt;div class="mooquee_item"&amp;gt;跑馬燈訊息第 2 則&amp;lt;/div&amp;gt;&lt;br /&gt;     &amp;lt;div class="mooquee_item"&amp;gt;跑馬燈訊息第 3 則&amp;lt;/div&amp;gt;&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/5921718512901059788/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/mooquee-marquee-with-mootools.html#comment-form" rel="replies" title="2 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5921718512901059788" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/5921718512901059788" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/mooquee-marquee-with-mootools.html" rel="alternate" title="Mooquee - Marquee with Mootools" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-7973418385312342588</id><published>2008-10-07T10:41:00.017+08:00</published><updated>2010-07-04T21:20:21.313+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="IE"/><title type="text">Internet Explorer 8 Web Slices</title><content type="html">Web Slices 是 Internet Explorer 8 的新功能之一，網頁開發者可以在單一網頁中指定多個區塊（Slices）供使用者訂閱到 IE8 新的最愛列（Favorites Bar）。&lt;br /&gt;&lt;br /&gt;現在很多網站都會提供 RSS（Really Simple Syndication）的網站內容訂閱服務。使用者只要利用 RSS 閱讀器訂閱內容，就可以方便獲得網站的更新資訊，而不需造訪網站檢閱是否有變更或新資訊。對於提供 RSS 服務的網站來說，它必須提供特定格式的 XML 檔案（亦即 RSS feed）的內容，才能供閱讀器下載及檢查更新。相較之下，Web Slices 並不需要個別的 Feed 檔案，而是直接在網頁中定義 Feed 項目，如以下範例：&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;div id="Div1" &lt;strong&gt;class="hslice"&lt;/strong&gt;&amp;gt;&lt;br /&gt;    &amp;lt;h4 &lt;strong&gt;class="entry-title"&lt;/strong&gt;&amp;gt;Web Slice Title&amp;lt;/h4&amp;gt;&lt;br /&gt;    &amp;lt;div &lt;strong&gt;class="entry-content"&lt;/strong&gt;&amp;gt;&lt;br /&gt;        This will appear in the preview window.&lt;br /&gt;    &amp;lt;/div&amp;gt;&lt;br /&gt;&amp;lt;/div&amp;gt;&lt;/pre&gt;&lt;span class="fullpost"&gt;如你所見，你只要在 HTML 標籤中透過 class 屬性，套用如上例粗體標示的樣式類別名稱，即可在網頁啟用 多個 Web Slice。一個最簡單的 Web Slice 至少要具備以下三個要素：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;一個套用 hslice 樣式類別的父元素。&lt;/li&gt;&lt;li&gt;父元素的必須具備唯一的 ID 識別名稱。&lt;/li&gt;&lt;li&gt;一個套用 entry-title 樣式類別的子元素。&lt;/li&gt;&lt;/ul&gt;當 IE 8 偵測到網頁有可用的 Web Slice 時，其工具列上的就會出現綠色的 &lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrZ3SrZblRKh90R1Tn-G1zqLUyILUk9GtnaC_wv5pc0R9f6U7QLV9FS4upvwlCS-T32WhJSbI8eM3UIFWGqzmMGWGrv134oTGcKhAmiYRalCPLB3HNzgg3Y_ELTqk29t9UyC6vc7kjWqk/s1600-h/icn_webslice.png"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrZ3SrZblRKh90R1Tn-G1zqLUyILUk9GtnaC_wv5pc0R9f6U7QLV9FS4upvwlCS-T32WhJSbI8eM3UIFWGqzmMGWGrv134oTGcKhAmiYRalCPLB3HNzgg3Y_ELTqk29t9UyC6vc7kjWqk/s320/icn_webslice.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5254296793960226066" /&gt;&lt;/a&gt; 圖示來提示使用者。同時，當使用者的滑鼠游標移至網頁中的 Web Slice 時也會出現相同的圖示。當使用者按下圖示就可訂閱 Web Slices，並將其新增至 [我的最愛] 列。只要使用者訂閱 Web Slices，便可以直接在 [我的最愛] 列開啟快顯視窗預覽到相關資訊。如果有興趣，你可以先體驗 eBay 實作 Web Slices 的專屬網站：&lt;a href="htt://ie8.ebay.com/"&gt;htt://ie8.ebay.com/&lt;/a&gt;。&lt;br /&gt;&lt;br /&gt;相關連結：&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc196991(VS.85).aspx"&gt;New RSS Features for Internet Explorer 8&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/cc848871(VS.85).aspx#creating"&gt;Internet Explorer 8 Web Slice Style Guide&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=ie8whitepapers&amp;ReleaseId=567"&gt;Internet Explorer 8 Beta 1 Whitepapers - Release WebSlices&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/7973418385312342588/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/internet-explorer-8-web-slices.html#comment-form" rel="replies" title="0 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/7973418385312342588" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/7973418385312342588" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/internet-explorer-8-web-slices.html" rel="alternate" title="Internet Explorer 8 Web Slices" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrZ3SrZblRKh90R1Tn-G1zqLUyILUk9GtnaC_wv5pc0R9f6U7QLV9FS4upvwlCS-T32WhJSbI8eM3UIFWGqzmMGWGrv134oTGcKhAmiYRalCPLB3HNzgg3Y_ELTqk29t9UyC6vc7kjWqk/s72-c/icn_webslice.png" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2573692172331948535.post-312506532582961293</id><published>2008-10-03T09:37:00.022+08:00</published><updated>2010-07-04T17:14:57.979+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AJAX"/><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type="text">AJAX DateTimePicker Extender</title><content type="html">在 Windows Forms 中，有 DateTimePicker 控制項可以用來選擇日期或編輯時間。然而，在 ASP.NET 中只有內建可選取日期的 Calendar Web 伺服器控制項，以及 AJAX Control Toolkit 提供的 Calendar 擴充項外，並沒有兼具選擇日期或編輯時間的 Web 控制項。所幸，&lt;a href="http://www.dynarch.com/projects/calendar/"&gt;jscalendar&lt;/a&gt; 正好可以滿足這樣的需求。它是一款功能強大且免費的 DHTML 日期選擇器，不僅內建多種的面板和色彩主題，還支援多國語言顯示介面。&lt;br /&gt;&lt;br /&gt;為了能方便引用到 ASP.NET 網頁中，於是自己便著手將 jscalendar 1.0 封裝到自訂的 AJAX DateTimePicker 擴充項控制項。&lt;br /&gt;&lt;a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIwCcdRvhOWnF4cuR3sw4529XIEMKjw2iAHetFqUCMAw7Ep5ivLPYKW_4V77wiaLOsOnIpaPj6QpkVkUFSKWfu9ubfBjMRwbAtYmxMxSCcuy0AbwzQLkaLQNz2l9H6dHC6Ygp6lQl2rhg/s1600-h/Calendar.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIwCcdRvhOWnF4cuR3sw4529XIEMKjw2iAHetFqUCMAw7Ep5ivLPYKW_4V77wiaLOsOnIpaPj6QpkVkUFSKWfu9ubfBjMRwbAtYmxMxSCcuy0AbwzQLkaLQNz2l9H6dHC6Ygp6lQl2rhg/s320/Calendar.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5252944302501501826" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class="fullpost"&gt;&lt;br /&gt;&lt;strong&gt;DateTimePicker 擴充項的屬性&lt;/strong&gt;&lt;br /&gt;&lt;table class="grid"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;屬性&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Align&lt;/td&gt;&lt;td&gt;指定快顯日曆的對齊方式，預設值為 "Br"。詳見&lt;a href="http://www.blogger.com/post-edit.g?blogID=2573692172331948535&amp;amp;postID=312506532582961293#AlignFormat"&gt;對齊方式格式&lt;/a&gt;說明。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Format&lt;/td&gt;&lt;td&gt;指示要套用到文字方塊中的日期顯示格式，期預設值為 "%Y-%m-%d"。詳見&lt;a href="http://www.blogger.com/post-edit.g?blogID=2573692172331948535&amp;amp;postID=312506532582961293#DateTimeFormat"&gt;自訂日期時間格式&lt;/a&gt;說明。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FirstDayOfWeek&lt;/td&gt;&lt;td&gt;以 0 到 6 指定每週的起始日，0 表示星期日，1 為星期一，依此類推。預設為星期日。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PopupButtonID&lt;/td&gt;&lt;td&gt;指定用來觸發顯示快顯日曆的控制項識別碼。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TargetControlID&lt;/td&gt;&lt;td&gt;指定顯示選取日期的 TextBox 控制項識別碼。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Theme&lt;/td&gt;&lt;td&gt;預設的日曆面板主題為 Aqua，你可以依照偏好變更為其他的面版樣式：Blue、Blue2、Brown、Green、System、Tas、Win2k1、Win2k2、Win2kCold1、Win2kCold2。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TimeMode&lt;/td&gt;&lt;td&gt;以 12 或 24 定義時間格式，預設為 12 小時制。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SingleClick&lt;/td&gt;&lt;td&gt;指定日期選擇是 Single-Click 或 Double-Click 模式。若指定為 true（預設值）則表示為 Single-Click 模式。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ShowsTime&lt;/td&gt;&lt;td&gt;指定是否顯示時間，若指定為 false（預設值）則表示不顯示。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WeekNumbers&lt;/td&gt;&lt;td&gt;指定是否顯示星期名稱，若指定為 true（預設值）則表示要顯示。&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;&lt;a name="AlignFormat"&gt;對齊方式格式&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;使用 Align 屬性可以指定快顯日曆的垂直對齊（Vertical Alignment）及水平對齊（Horizontal Alignment）方式。在 Align 屬性中的第一個字元表示垂直對齊方式，其格式規範如下：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th&gt;格式&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;T&lt;/td&gt;&lt;td&gt;下邊緣與目標元素的上邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;t&lt;/td&gt;&lt;td&gt;下邊緣與目標元素的下邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;c&lt;/td&gt;&lt;td&gt;垂直置中於目標元素。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;b&lt;/td&gt;&lt;td&gt;上邊緣與目標元素的上邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;上邊緣與目標元素的下邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;第二個字元表示水平對齊方式，其格式規範如下：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tr&gt;&lt;th&gt;格式&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;L&lt;/td&gt;&lt;td&gt;右邊緣與目標元素的左邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;l&lt;/td&gt;&lt;td&gt;左邊緣與目標元素的左邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;c&lt;/td&gt;&lt;td&gt;水平置中於目標元素。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;r&lt;/td&gt;&lt;td&gt;右邊緣與目標元素的右邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;R&lt;/td&gt;&lt;td&gt;左邊緣與目標元素的右邊緣相鄰對齊。&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;&lt;a name="DateTimeFormat"&gt;自訂日期時間格式&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;以下是使用 Format 屬性指定自訂日期時間格式的規範：&lt;br /&gt;&lt;table class="grid"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;格式&lt;/th&gt;&lt;th&gt;說明&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%a&lt;/td&gt;&lt;td&gt;表示星期名稱的縮寫。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%A&lt;/td&gt;&lt;td&gt;表示星期名稱的全名。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%b&lt;/td&gt;&lt;td&gt;表示月份名稱的縮寫&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%B&lt;/td&gt;&lt;td&gt;表示月份名稱的全名。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%C&lt;/td&gt;&lt;td&gt;表示世紀的數字。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%d&lt;/td&gt;&lt;td&gt;以 00 到 31 表示月份的日期。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%e&lt;/td&gt;&lt;td&gt;以 0 到 31 表示月份的日期。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%H&lt;/td&gt;&lt;td&gt;以 00 到 23 的數字來表示小時。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%I&lt;/td&gt;&lt;td&gt;以 01 到 12 的數字來表示小時。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%j&lt;/td&gt;&lt;td&gt;本年第幾天。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%k&lt;/td&gt;&lt;td&gt;以 0 到 23 的數字來表示小時。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%l&lt;/td&gt;&lt;td&gt;以 1 到 12 的數字來表示小時。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%m&lt;/td&gt;&lt;td&gt;以 01 到 12 的數字代表月份。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%M&lt;/td&gt;&lt;td&gt;以 00 到 59 的數字來表示分鐘。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%n&lt;/td&gt;&lt;td&gt;表示換行字元。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%p&lt;/td&gt;&lt;td&gt;表示 PM 或 AM。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%P&lt;/td&gt;&lt;td&gt;表示 pm 或 am。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%S&lt;/td&gt;&lt;td&gt;以 00 到 59 的數字來表示秒數。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%s&lt;/td&gt;&lt;td&gt;自 Epoch 系統時間開始所經過的秒數。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%t&lt;/td&gt;&lt;td&gt;表示 Tab 字元。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%U, %W, %V&lt;/td&gt;&lt;td&gt;本年的第幾周。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%u&lt;/td&gt;&lt;td&gt;以星期一為起始序數，從 1 到 7 的數字代表星期的日期。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%w&lt;/td&gt;&lt;td&gt;以星期日為起始序數，從 0 到 6 的數字代表星期的日期。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%y&lt;/td&gt;&lt;td&gt;以兩個位數的數字來表示年份。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%Y&lt;/td&gt;&lt;td&gt;以四個位數的數字來表示年份。&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;%%&lt;/td&gt;&lt;td&gt;將 % 字元顯示為常值（Literal）。&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;範例&lt;/strong&gt;&lt;br /&gt;下列範例會建立能讓使用者選擇日期及時間的日曆：&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;asp:TextBox ID="TextBox1" runat="server"&amp;gt;&amp;lt;/asp:TextBox&amp;gt;&lt;br /&gt;&amp;lt;ace:DateTimePickerExtender ID="DateTimePickerExtender1" runat="server"&lt;br /&gt;TargetControlID="TextBox1"&lt;br /&gt;Format="%Y-%m-%d %H:%M"&lt;br /&gt;ShowsTime="true"&lt;br /&gt;SingleClick="false" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;你也可以加入按鈕來開啟快顯日曆：&lt;br /&gt;&lt;pre class="prettyprint"&gt;&amp;lt;asp:TextBox ID="TextBox2" runat="server"&amp;gt;&amp;lt;/asp:TextBox&amp;gt;&lt;br /&gt;&amp;lt;asp:Button runat="server" ID="Button2" Text="..." OnClientClick="return false;" /&amp;gt;    &lt;br /&gt;&amp;lt;ace:DateTimePickerExtender ID="DateTimePickerExtender2" runat="server"&lt;br /&gt;TargetControlID="TextBox2"&lt;br /&gt;PopupButtonID="Button2"&lt;br /&gt;Format="%Y-%m-%d %H:%M"&lt;br /&gt;ShowsTime="true" /&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;nobr&gt;&lt;img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinmKZ-psi6bqzyZNlIhYfYxWtnx8UAU_LxICmxlKh41OJivg-sDElWiL8UzP4qno45i14mTYEYuDoi-vZIYlM6oOTKX4UCYQiFQ5QvV8wF6pnZ3yc3LbhsBMbVjUmfV65GGRgjGUfxqe4/s320/download.gif" align="absmiddle" border="0" alt="" /&gt; &lt;a href="http://cid-9dd633e0cd9ff6c8.skydrive.live.com/self.aspx/Source/DateTimePicker.zip"&gt;Download source code - for ASP.NET 3.5&lt;/a&gt;&lt;/nobr&gt;&lt;br /&gt;&lt;br /&gt;資料來源：&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/jscalendar/"&gt;http://sourceforge.net/projects/jscalendar/&lt;/a&gt;&lt;/span&gt;</content><link href="http://renjin.blogspot.com/feeds/312506532582961293/comments/default" rel="replies" title="張貼留言" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/ajax-datetimepicker-extender.html#comment-form" rel="replies" title="15 個意見" type="text/html"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/312506532582961293" rel="edit" type="application/atom+xml"/><link href="http://www.blogger.com/feeds/2573692172331948535/posts/default/312506532582961293" rel="self" type="application/atom+xml"/><link href="http://renjin.blogspot.com/2008/10/ajax-datetimepicker-extender.html" rel="alternate" title="AJAX DateTimePicker Extender" type="text/html"/><author><name>renjin</name><uri>http://www.blogger.com/profile/01940339705719517441</uri><email>noreply@blogger.com</email><gd:image height="16" rel="http://schemas.google.com/g/2005#thumbnail" src="https://img1.blogblog.com/img/b16-rounded.gif" width="16"/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" height="72" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjIwCcdRvhOWnF4cuR3sw4529XIEMKjw2iAHetFqUCMAw7Ep5ivLPYKW_4V77wiaLOsOnIpaPj6QpkVkUFSKWfu9ubfBjMRwbAtYmxMxSCcuy0AbwzQLkaLQNz2l9H6dHC6Ygp6lQl2rhg/s72-c/Calendar.jpg" width="72"/><thr:total>15</thr:total></entry></feed>