Printing PDF File from ASP.NET

0 comments
使用 PDF(Portable Document Format)文件格式的好處在於,不論使用何種電腦平台或作業系統,都能忠實重現文件的原貌,也不會因為印表機的不同而影響排版。因此,PDF 格式在不同設備上輸出列印的一致性,非常適合用在印表機列印輸出的需求。

在網頁設計實務上,需要動態產生文件及講求排版格式的列印功能亦頗為常見。本文將示範如何使用 iTextShap 建立 PDF 文件,並加入 JavaScript 指令碼透過 Acrobat API 將文件自動輸出至指定的印表機。

下列程式碼範例會假設已經在 ASP.NET Web 網頁建立列印按鈕,並指定如下的 Click 事件處理常式。範例中的 PrintButton_Click 方法,會在指定的目錄下將建立含有列印指令碼的 PDF 文件,並透過泛型處理常式將文件傳送到用戶端,然後輸出至使用者的印表機。
protected void PrintButton_Click(object sender, EventArgs e)
{
Document document = new Document();
MemoryStream ms = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, ms);
document.Open();

// 加入自動列印指令碼
writer.AddJavaScript(@"
var pp = this.getPrintParams();
pp.interactive = pp.constants.interactionLevel.silent;
pp.pageHandling = pp.constants.handling.none;
var fv = pp.constants.flagValues;
pp.flags |= fv.setPageSize;
pp.flags |= (fv.suppressCenter | fv.suppressRotate);
this.print(pp);
");

document.Add(new Paragraph("Testing Silent Printing with iTextSharp."));
document.Close();

Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "inline; filename=Report.pdf");
Response.BinaryWrite(ms.ToArray());
Response.End();
}

參考資料:
Silent Printing on Web based Java Application

繼續閱讀...

Returning Value from ASPxPopupControl

0 comments
ASPxPopupControl 是 Developer Express 在 ASPxperience Suite 裡面所提供的 Web 控制項。你不僅可以利用它填入 HTML 內容外,也可以指定特定的網頁來為你的網頁加入快顯視窗功能。

當你使用 ASPxPopupControl 的 ContentUrl 屬性設定開啟網頁時,它會建立內嵌框架載入網頁內容。為了利於在內嵌網頁中傳遞值給主網頁及隱藏快顯視窗所需的物件參考,需在其 init 事件加入必要的初始化程式碼。
<%@ Page Language="C#" AutoEventWireup="true" %>
<html>
<head runat="server">
<title>Returning Value from ASPxPopupControl</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table border="0">
<tr>
<td>
<dx:ASPxTextBox ID="supplierTextBox" runat="server"
ClientInstanceName="supplierTextBox" Width="80" />
</td>
<td>
<dx:ASPxButton ID="popupButton" runat="server" Text="..." />
</td>
</tr>
</table>
<dx:ASPxPopupControl ID="suppliersPopup" runat="server"
ClientInstanceName="suppliersPopup" AllowDragging="True"
AllowResize="True" CloseAction="CloseButton"
ContentUrl="SlavePage.aspx" Width="400" Height="450"
ContentStyle-Paddings-Padding="2" HeaderText="Select Supplier"
PopupElementID="popupButton">
<ClientSideEvents Init="function(s, e) {
var iframe = s.GetContentIFrame();
iframe.contentLoaded = false;
var controlCollection = ASPxClientControl.GetControlCollection();
iframe.popupArguments = {
popupContainer: controlCollection.Get('suppliersPopup'),
controlToAssign: controlCollection.Get('supplierTextBox')
};
}"></ClientSideEvents>
</dx:ASPxPopupControl>
</div>
</form>
</body>
</html>

以下程式碼示範如何在內嵌框架頁面中傳值給主網頁並隱藏快顯視窗:
<%@ Page Language="C#" AutoEventWireup="true" %>
<html>
<head runat="server">
<title>Select Supplier</title>
<script type="text/javascript">
function getOuterFrame() {
var iframes = window.parent.document.getElementsByTagName("iframe");
for (var i = 0, len = iframes.length; i < len; i++) {
var doc = iframes[i].contentDocument || iframes[i].contentWindow.document;
if (doc === document) {
return iframes[i];
}
}
return null;
}
function hidePopupWindow() {
var outerFrame = getOuterFrame();
if (outerFrame !== null) {
outerFrame.popupArguments.popupContainer.Hide();
}
}
function setReturnValue(v) {
var outerFrame = getOuterFrame();
if (outerFrame !== null) {
var controlToAssign = outerFrame.popupArguments.controlToAssign;
if (controlToAssign) {
controlToAssign.SetText(v);
}
}
hidePopupWindow();
}
</script>
<script runat="server">
void OkButton_Click(object sender, EventArgs e)
{
if (grid.FocusedRowIndex > -1)
{
object key = grid.GetRowValues(grid.FocusedRowIndex, grid.KeyFieldName);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(),
"SetReturnValue", "setReturnValue('" + key.ToString() + @"');
", true);
}
}
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<dx:ASPxGridView ID="grid" runat="server"
ClientInstanceName="grid" DataSourceID="NorthwindDataSource"
KeyFieldName="SupplierID" AutoGenerateColumns="false" Width="100%">
<Columns>
<dx:GridViewDataCheckColumn>
<DataItemTemplate>
<input type="radio" name="radioButton" />
</DataItemTemplate>
</dx:GridViewDataCheckColumn>
<dx:GridViewDataColumn FieldName="CompanyName" Caption="Company Name" />
<dx:GridViewDataColumn FieldName="ContactName" Caption="Contact Name" />
</Columns>
<SettingsBehavior AllowFocusedRow="True" />
<ClientSideEvents FocusedRowChanged="function(s, e) {
var row = s.GetRow(s.GetFocusedRowIndex());
if(__aspxIE)
row.cells[0].childNodes[0].checked = true;
else
row.cells[0].childNodes[1].checked = true;
}" />
</dx:ASPxGridView>
<br />
<table border="0" align="center">
<tr>
<td>
<dx:ASPxButton ID="OkButton" runat="server" Text="OK"
OnClick="OkButton_Click" />
</td>
<td>
<dx:ASPxButton ID="CancelButton" runat="server" Text="Cancel">
<ClientSideEvents Click="function(s, e) {
hidePopupWindow();
}" />
</dx:ASPxButton>
</td>
</tr>
</table>
<asp:AccessDataSource ID="NorthwindDataSource" runat="server"
DataFile="~/App_Data/Northwind.mdb"
SelectCommand="SELECT * FROM Suppliers"></asp:AccessDataSource>
</div>
</form>
</body>
</html>

Download sample code

繼續閱讀...

SQL Server 連線共用的問題

0 comments
在預設的情況下,SQL Server 的 .NET Framework 資料提供者會自動提供連線共用(Connection Pooling),以利提升應用程式的延展性及效能。然而,當 ADO.NET 用戶端嘗試使用共用連線時,有可能會遇到如下的例外狀況:
在傳送要求至伺服器時發生傳輸層級的錯誤。 (provider: TCP 提供者, error: 0 - 遠端主機已強制關閉一個現存的連線。)

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.)

如果共用連線集區的可用連線與伺服器的連接已嚴重損毀,例如:伺服器重新啟動、容錯移轉、使用者處理序被刪除等,連線共用器並無法立即發現異常,直到將其傳回至 ADO.NET 呼叫端並嘗試與伺服器進行通訊後,才會偵測到連接已損毀。當發生此情況時,連線共用器會從集區中移除該連線,並且擲回如上的例外狀況。

連線共用機制並非能完全保證可用連線的有效性,除非你在連線字串中指定 Pooling=false 明確停用,否則你難以避免此類問題發生。除此之外,建議你在資料存取程式碼中加入例外處理常式因應,或是使用 Retryer Pattern 做最佳的容錯處理。

參考資料:
SQL Server 連接共用 (ADO.NET)

繼續閱讀...

ASP.NET DateDropDown Control

0 comments
DateDropDown 是一個使用 UpdatePanel 控制項所建立的連動下拉式日期使用者控制項(User Control)。你可以設定 MinDate 和 MaxDate 屬性,來限制使用者能夠選取的日期範圍,同時也可以搭配驗證控制項檢查使用者輸入的值。

DateDropDown 控制項的完整程式碼如下:
DateDropDown.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="DateDropDown.ascx.cs" 
Inherits="DateDropDown" %>
<asp:UpdatePanel ID="uxUpdatePanel" runat="server">
<ContentTemplate>
<table cellpadding="0" cellspacing="0" border="0">
<tr>
<td><asp:DropDownList id="uxYearList" runat="server" AutoPostBack="true"
OnSelectedIndexChanged="uxYearList_SelectedIndexChanged">
</asp:DropDownList></td>
<td>年</td>
<td><asp:DropDownList id="uxMonthList" runat="server" AutoPostBack="true"
OnSelectedIndexChanged="uxMonthList_SelectedIndexChanged">
<asp:ListItem Text="請選擇"></asp:ListItem>
</asp:DropDownList></td>
<td>月</td>
<td><asp:DropDownList id="uxDayList" runat="server">
<asp:ListItem Text="請選擇"></asp:ListItem>
</asp:DropDownList></td>
<td>日</td>
</tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>
<script language="javascript" type="text/javascript">
Sys.WebForms.PageRequestManager.getInstance().add_beginRequest(
function(sender, e) {
var elem = e.get_postBackElement();
if (elem.id == '<%= uxYearList.ClientID %>') {
$get('<%= uxMonthList.ClientID %>').disabled = true;
$get('<%= uxDayList.ClientID %>').disabled = true;
$get('<%= this.ClientID %>').value = '';
}
else if (elem.id == '<%= uxMonthList.ClientID %>') {
$get('<%= uxDayList.ClientID %>').disabled = true;
$get('<%= this.ClientID %>').value = '';
}
});
</script>

DateDropDown.ascx.cs
using System;
using System.Reflection;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

/// <summary>
/// 連動下拉式日期控制項
/// </summary>
[ValidationProperty("Text")]
public partial class DateDropDown : System.Web.UI.UserControl
{
readonly int _maxYear = DateTime.Today.Year + 20;
readonly int _minYear = DateTime.Today.Year - 20;
const string _promptText = "請選擇";

protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
Initialize();
}

ScriptManager.RegisterHiddenField(uxUpdatePanel, this.ClientID, this.Text);
RegisterScript();
}

private void Initialize()
{
if (Initialized)
return;

Initialized = true;
PopulateYearList();
AssignValidation();
}

private void RegisterScript()
{
string script = string.Format(
@"$get('{0}').onchange = function() {{
$get('{1}').value =
($get('{2}').selectedIndex > 0 && $get('{3}').selectedIndex > 0
&& this.selectedIndex > 0) ?
$get('{2}').value + '-' + $get('{3}').value + '-' + this.value : '';
}};
", uxDayList.ClientID, ClientID, uxYearList.ClientID, uxMonthList.ClientID);

ScriptManager.RegisterStartupScript(Page, Page.GetType(), UniqueID + "_onchange",
script, true);
}

private bool Initialized
{
set
{
ViewState["Initialized"] = value;
}

get
{
if (ViewState["Initialized"] == null)
ViewState["Initialized"] = false;

return (bool)ViewState["Initialized"];
}
}

/// <summary>
/// 取得選取的日期字串
/// </summary>
public string Text
{
get
{
if (uxYearList.SelectedIndex == 0 || uxMonthList.SelectedIndex == 0
|| uxDayList.SelectedIndex == 0)
return string.Empty;

return new DateTime(int.Parse(uxYearList.SelectedValue),
int.Parse(uxMonthList.SelectedValue),
int.Parse(uxDayList.SelectedValue)).ToString("yyyy-MM-dd");
}
}

/// <summary>
/// 取得或設定驗證群組名稱
/// </summary>
public string ValidationGroup
{
get
{
return (string)ViewState["ValidationGroup"];
}
set
{
ViewState["ValidationGroup"] = value;
}
}

/// <summary>
/// 最小日期值
/// </summary>
public DateTime MinDate
{
set
{
ViewState["MinDate"] = value;
}

get
{
if (ViewState["MinDate"] == null)
ViewState["MinDate"] = new DateTime(_minYear, 1, 1);

return (DateTime)ViewState["MinDate"];
}
}

/// <summary>
/// 最大日期值
/// </summary>
public DateTime MaxDate
{
set
{
ViewState["MaxDate"] = value;
}

get
{
if (ViewState["MaxDate"] == null)
ViewState["MaxDate"] = new DateTime(_maxYear, 12, 31);

return (DateTime)ViewState["MaxDate"];
}
}

/// <summary>
/// 取得或設定選取的日期
/// </summary>
public DateTime SelectedDate
{
set
{
if (value < MinDate || value > MaxDate)
throw new ArgumentOutOfRangeException("SelectedDate",
"The value should be between 'MinDate' and 'MaxDate'.");

Initialize();
uxYearList.SelectedValue = value.Year.ToString();
(uxYearList as IPostBackDataHandler).RaisePostDataChangedEvent();
uxMonthList.SelectedValue = value.Month.ToString();
(uxMonthList as IPostBackDataHandler).RaisePostDataChangedEvent();
uxDayList.SelectedValue = value.Day.ToString();
ScriptManager.RegisterExpandoAttribute(uxUpdatePanel,
ClientID, "value", Text, false);
}

get
{
Initialize();

DateTime selectedValue;
if (DateTime.TryParse(Text, out selectedValue))
return selectedValue;

return DateTime.MinValue;
}
}

protected void AssignValidation()
{
foreach (Control control in this.Controls)
{
PropertyInfo property = control.GetType().GetProperty("ValidationGroup");
if (property != null)
{
property.SetValue(control, ValidationGroup, null);
}
}
}

private void PopulateYearList()
{
uxYearList.Items.Clear();
uxYearList.Items.Add(new ListItem(_promptText));

for (int y = MinDate.Year; y <= MaxDate.Year; y++)
{
uxYearList.Items.Add(new ListItem(y.ToString(), y.ToString()));
if (SelectedDate != DateTime.MinValue && y == SelectedDate.Year)
{
uxYearList.Items.FindByValue(y.ToString()).Selected = true;
}
}
}

private void PopulateMonthList(int year)
{
uxMonthList.Items.Clear();
uxMonthList.Items.Add(new ListItem(_promptText));

int minMonth = MinDate.Year == year ? MinDate.Month : 1;
int maxMonth = MaxDate.Year == year ? MaxDate.Month : 12;

for (int m = minMonth; m <= maxMonth; m++)
{
uxMonthList.Items.Add(new ListItem(m.ToString(), m.ToString()));
if (SelectedDate != DateTime.MinValue && m == SelectedDate.Month)
{
uxMonthList.Items.FindByValue(m.ToString()).Selected = true;
}
}

uxMonthList.Enabled = true;
}

private void PopulateDayList(int year, int month)
{
uxDayList.Items.Clear();
uxDayList.Items.Add(new ListItem(_promptText));

int minDay = MinDate.Year == year && MinDate.Month == month ? MinDate.Day : 1;
int maxDay = MaxDate.Year == year && MaxDate.Month == month ?
MaxDate.Day : DateTime.DaysInMonth(year, month);

for (int d = minDay; d <= maxDay; d++)
{
uxDayList.Items.Add(new ListItem(d.ToString(), d.ToString()));
if (SelectedDate != DateTime.MinValue && d == SelectedDate.Day)
{
uxDayList.Items.FindByValue(d.ToString()).Selected = true;
}
}

uxDayList.Enabled = true;
}

protected void uxYearList_SelectedIndexChanged(object sender, EventArgs e)
{
if (uxYearList.SelectedIndex == 0)
{
uxMonthList.SelectedIndex = uxDayList.SelectedIndex = 0;
uxMonthList.Enabled = uxDayList.Enabled = false;
return;
}

PopulateMonthList(int.Parse(uxYearList.SelectedValue));
}

protected void uxMonthList_SelectedIndexChanged(object sender, EventArgs e)
{
if (uxMonthList.SelectedIndex == 0)
{
uxDayList.SelectedIndex = 0;
uxDayList.Enabled = false;
return;
}

PopulateDayList(int.Parse(uxYearList.SelectedValue),
int.Parse(uxMonthList.SelectedValue));
}
}

下列程式碼範例要求使用者輸入一個介於 2009-07-01 到 2010-07-01 之間的日期,並使用 RequiredFieldValidator 來確認控制項的輸入。
<uc1:DateDropDown ID="DateDropDown1" runat="server" ValidationGroup="DateDropDown" 
MinDate="2009-07-01" MaxDate="2010-07-01" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server"
ControlToValidate="DateDropDown1" ValidationGroup="DateDropDown"
ErrorMessage="Please enter a Date!"></asp:RequiredFieldValidator>


Download DateDropDown.zip

繼續閱讀...