2014年9月6日 星期六

[ASP.NET]找出控制項的方法 FindControl

在ASP.NET,FindControl的用途通常是找出

  1. 自動產生的控制項
  2. 被包裝起來的控制項 (例如:GridView FormView)
而FindControl的使用方法是
  1. 在程式碼中建立控制項
  2. 指定控制項為找到的控制項
  3. 自由的控制找到的控制項

一般的搜尋方式(HTML)

   1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="FindControl.WebForm1" %>
   2:   
   3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4:   
   5:  <html xmlns="http://www.w3.org/1999/xhtml">
   6:  <head runat="server">
   7:      <title>找出控制項的方法</title>
   8:  </head>
   9:  <body>
  10:      <form id="form1" runat="server">
  11:      <div>
  12:      
  13:          <asp:TextBox ID="TextBox1" runat="server">這裡是TextBox</asp:TextBox>
  14:          <br />
  15:          <asp:Button ID="Button1" runat="server" Text="這裡是Button" />
  16:          <br />
  17:          <br />
  18:          <asp:Button ID="btnFind" runat="server" onclick="btnFind_Click" 
  19:              Text="找出上面兩個控制項" />
  20:          <br />
  21:          <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
  22:      
  23:      </div>
  24:      </form>
  25:  </body>
  26:  </html>


程式碼

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.UI;
   6:  using System.Web.UI.WebControls;
   7:   
   8:  namespace FindControl
   9:  {
  10:      public partial class WebForm1 : System.Web.UI.Page
  11:      {
  12:          protected void Page_Load(object sender, EventArgs e)
  13:          {
  14:   
  15:          }
  16:   
  17:          protected void btnFind_Click(object sender, EventArgs e)
  18:          {
  19:              // 確認TextBox是否存在
  20:              if (this.FindControl("TextBox1") != null)
  21:              {
  22:                  // 找出 TextBox1
  23:                  TextBox Findtxt = (TextBox)this.FindControl("TextBox1");
  24:                  // 顯示到 Label1 
  25:                  Label1.Text = Findtxt.Text+"<br />";
  26:              }
  27:   
  28:              // 確認 Button 是否存在
  29:              if (this.FindControl("Button1") != null)
  30:              {
  31:                  // 找出 TextBox1
  32:                  Button Findbtn = (Button)this.FindControl("Button1");
  33:                  // 顯示到 Label1 
  34:                  Label1.Text += Findbtn.Text;
  35:              }
  36:          }
  37:      }
  38:  }

在有主板頁面的情況

如果網頁本身就在主板頁面的話 就不能夠使用一般的方法來尋找控制項

一般的搜尋方式找有主板頁面的控制項都會碰到這個問題
因為控制項已經變成了包在主板頁面內,所以控制項的ID也會變得不一樣
如果要找到主板頁面內的控制項的話,先要找出主板頁面,再找出控制項
以下是主板頁面的方式(HTML)
   1:  <%@ Page Title="" Language="C#" MasterPageFile="~/Site1.Master" AutoEventWireup="true" CodeBehind="MasterForm.aspx.cs" Inherits="FindControl.MasterForm" %>
   2:  <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
   3:  </asp:Content>
   4:  <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
   5:      <asp:TextBox ID="TextBox1" runat="server" Width="164px">這個是主板頁面內的TexbBox</asp:TextBox>
   6:      <br />
   7:      <asp:Button ID="Button1" runat="server" Text="這個是主板頁面內的Button" />
   8:      <br />
   9:      <br />
  10:      <asp:Button ID="btnFind" runat="server" onclick="btnFind_Click" Text="找出控制項" />
  11:      <br />
  12:      <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
  13:      <br />
  14:  </asp:Content>
程式碼

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.UI;
   6:  using System.Web.UI.WebControls;
   7:   
   8:  namespace FindControl
   9:  {
  10:      public partial class MasterForm : System.Web.UI.Page
  11:      {
  12:          protected void Page_Load(object sender, EventArgs e)
  13:          {
  14:   
  15:          }
  16:   
  17:          protected void btnFind_Click(object sender, EventArgs e)
  18:          {
  19:              // 找出在主板頁面內的按鈕
  20:              if (Master.FindControl("ContentPlaceHolder1").FindControl("Button1") != null)
  21:              {
  22:                  //找出 Button1
  23:                  Button btn1 = (Button)Master.FindControl("ContentPlaceHolder1").FindControl("Button1");
  24:                  // 將 Button1 內容顯示在 Label1
  25:                  Label1.Text = btn1.Text+"<br />";
  26:              }
  27:   
  28:              // 找出在主板頁面內的文字方塊
  29:              if (Master.FindControl("ContentPlaceHolder1").FindControl("TextBox1") != null)
  30:              {
  31:                  //找出 TextBox1
  32:                  TextBox txt1 = (TextBox)Master.FindControl("ContentPlaceHolder1").FindControl("TextBox1");
  33:                  // 將 TextBox1 內容顯示在 Label1
  34:                  Label1.Text += txt1.Text;
  35:              }
  36:          }
  37:      }
  38:  }
程式下載

參考資料

How to: Reference ASP.NET Master Page Content
[習題].FindControl()方法 與 PlaceHolder控制項 #1(動態加入「子控制項」,因Page_Load而發生的錯誤)

2014年8月2日 星期六

[ASP.NET]SqlBulkCopy 大量的資料庫輸入

因上次介紹了 Excel 匯入的方法,所以這一次也來介紹一個相關聯的大量資料庫寫入方法。

Excel 匯入方法
[ASP.NET]讀取 Excel 的方式 - 使用 NPOI 方式
[ASP.NET]讀取 Excel 的方式 - 使用 Excel模組 方式

就目前所知的資料庫寫入伺服器的方法有兩種

  • 使用 AddWithValue 的方法寫入
    • 宣告 資料庫連結SqlConnection 與 資料庫指令SqlCommand
    • SqlCommand 下新增指令 ( Insert into ... values ... )
    • 設定參數 SqlParameter 不設定的話會有 Sql injection 的問題
    • 如果是要寫入多筆資料的話,就是使用 for 一筆一筆的輸入
    • 但是只要有資料輸入出錯的話 (資料欄位型別出錯之類的) 上一筆輸入成功的資料還是會寫入,就會變成輸入成功的寫進資料庫了,但是到出錯那個地方就斷了的窘境。
  • 使用 SqlBulkCopy 的方法寫入
    • 宣告 資料庫連結SqlConnection
    • 寫入的方法通常是把想要寫入的資料放到 DataTable
    • 輸入要寫入的 資料表
    • 對照 資料庫欄位 與 DataTable的欄位
    • 最後使用 WriteToServer(DataTable) 寫入資料庫即可

HTML:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="SqlBulkCopy.WebForm1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    
        <asp:Button ID="btn100" runat="server" onclick="btn100_Click" Text="輸入百個隨機資料" />
        <br />
    
    </div>
    </form>
</body>
</html>
asp.cs:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.UI;
   6:  using System.Web.UI.WebControls;
   7:   
   8:  // 使用 DataTable
   9:  using System.Data;
  10:  // 使用 Sql連結與指令
  11:  using System.Data.SqlClient;
  12:   
  13:   
  14:   
  15:  namespace SqlBulkCopy
  16:  {
  17:      public partial class WebForm1 : System.Web.UI.Page
  18:      {
  19:          protected void Page_Load(object sender, EventArgs e)
  20:          {
  21:   
  22:          }
  23:   
  24:          protected void btn100_Click(object sender, EventArgs e)
  25:          {
  26:              // 設定資料庫連結
  27:              SqlConnection conn = new SqlConnection(System.Web.Configuration.WebConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
  28:              // 建立 DataTable
  29:              DataTable dt = new DataTable();
  30:              // 加入欄位
  31:              dt.Columns.Add("Num1");
  32:              dt.Columns.Add("Num2");
  33:              dt.Columns.Add("Num3");
  34:   
  35:              // 隨機輸入值到 DataTable
  36:              // 欄位迴圈值
  37:              for (int row = 0; row < 100; row++) 
  38:              {
  39:                  // 建立 DataRow
  40:                  DataRow dr = dt.NewRow();
  41:   
  42:                  for (int col = 0; col < 3; col++) // 列迴圈值
  43:                  {
  44:                      // 建立亂數                 避免重複值出現
  45:                      Random rnd = new Random(Guid.NewGuid().GetHashCode());
  46:                      // 1000的亂數值
  47:                      int num = rnd.Next(1000);
  48:                      // 加入到 DataRow
  49:                      dr[col] = num;
  50:                  }
  51:                  // DataRow 加到 DataTable
  52:                  dt.Rows.Add(dr);
  53:              }
  54:   
  55:              // 不好的示範 專案的名稱與SqlBulkCopy類別 撞到
  56:              System.Data.SqlClient.SqlBulkCopy sbc = new System.Data.SqlClient.SqlBulkCopy(conn);
  57:   
  58:              // 複製的目的地資料表
  59:              sbc.DestinationTableName = "dbo.DataInput";
  60:   
  61:              // 對照 資料表欄位
  62:              sbc.ColumnMappings.Add("Num1", "Num1");
  63:              sbc.ColumnMappings.Add("Num2", "Num2");
  64:              sbc.ColumnMappings.Add("Num3", "Num3");
  65:   
  66:              // 開啟資料庫連結
  67:              conn.Open();
  68:   
  69:              // 之後放進DataTable的資料
  70:              sbc.WriteToServer(dt);
  71:   
  72:              sbc.Close();
  73:              conn.Close();
  74:   
  75:              ClientScript.RegisterClientScriptBlock(this.GetType(), "寫入成功", "<script>alert('寫入成功');</script>");
  76:          }
  77:      }
  78:  }

程式下載

參考資料
(C#)使用SqlBulkCopy複製資料表到資料庫
DataColumn.DataType 屬性
請問執行asp.net後出現『字串或二進位資料會被截斷。陳述式已經結束』
[C#] 隨機產生值 v.s. Unity 隨機產生值

2014年7月28日 星期一

[ASP.NET]讀取 Excel 的方式 - 使用 NPOI 方式

繼上一次的 Excel 讀取方式
[ASP.NET]讀取 Excel 的方式 - 使用 Excel模組 方式

這次要說明的是另一個讀取 Excel 方式 就是使用 NPOI 的方式
NPOI (POI for .NET) 是從 POI  移植過來的 .NET版

POI 是 Apache 的開放原始碼的 Java 函式庫
專門用來讀取大部分 Microsoft Office的檔案格式

因為目前只有學習ASP.NET的東西,所以只有講解 NPOI 的部分
  • NPOI 是個額外的套件,取得的方式可透過 網站下載 或使用 Microsoft Visual Studio 內的 NuGet 套件進行安裝
  • 引用的函式分別是 
    • HSSF 使用於 Excel 2003 
    • XSSF 使用於 Excel 2007
    • XWPF 使用於 Word 2007
  • 引用的方式為 
    using NPOI.HSSF.UserModel;
  • 似乎只能讀取 2007 版本以下的 Excel 檔
  • 在Excel內編輯過的資料,就算刪除了也會讀進 ( 就變成了空白欄位 )
因為範例很多,所以只提供檔案下載



參考資料

NPOI教學

NPOI.FillPattern 使用方法

Memory Stream 使用方法
[VB.NET][C#.NET] MemoryStream / BufferedStream 類別



2014年7月26日 星期六

[ASP.NET]讀取 Excel 的方式 - 使用 Excel模組 方式

在寫入資料庫的網站上 (尤其是後台)
匯入與匯出 Excel 檔是一個很重要的功能
尤其是 再輸入大量資料的時候。

目前所知的匯入Excel 檔的方式有兩個:
這次先介紹直接使用 Excel模組的方式
  • 最正統的方式,也是很麻煩的方式
  • 這個方法主要是從我們的電腦上找出 Excel的執行程式來執行
  • 使用加入參考的方式來匯入 Excel 模組
  • 也就是說如果需要自己架設伺服器的話,那台伺服器上就必須安裝 Excel
  • 此方法會有資源占用的問題,處理完之後記得釋放資源
以下是參考 所寫出的程式
[ASP.net WebForm] 把Excel資料匯入資料庫的懶人Code分享 - Microsoft.office.Interop.Excel篇

HTML 碼

   1:  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="Excel_匯入_正統_.WebForm1" %>
   2:   
   3:  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   4:   
   5:  <html xmlns="http://www.w3.org/1999/xhtml">
   6:  <head runat="server">
   7:      <title></title>
   8:  </head>
   9:  <body>
  10:      <form id="form1" runat="server">
  11:      <div>
  12:      
  13:          <asp:FileUpload ID="FuFile" runat="server" />
  14:          <br />
  15:          <asp:GridView ID="GridView1" runat="server">
  16:          </asp:GridView>
  17:          <br />
  18:          <asp:Button ID="btnOK" runat="server" onclick="btnOK_Click" Text="匯入Excel" />
  19:      
  20:      </div>
  21:      </form>
  22:  </body>
  23:  </html>

CS 檔


   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.UI;
   6:  using System.Web.UI.WebControls;
   7:  using System.Data;
   8:   
   9:  // 引用 Microsoft Excel 參考
  10:  using Microsoft.Office.Interop;
  11:  using Microsoft.Office.Interop.Excel;
  12:   
  13:  namespace Excel_匯入_正統_
  14:  {
  15:      public partial class WebForm1 : System.Web.UI.Page
  16:      {
  17:          // 使用 Excel 的應用程式
  18:          Microsoft.Office.Interop.Excel.Application xlApp = null;
  19:          // WorkBook
  20:          Workbook wb = null;
  21:          // 工作表
  22:          Worksheet ws = null;
  23:          // 加入範圍
  24:          Range aRange = null;
  25:   
  26:          protected void Page_Load(object sender, EventArgs e)
  27:          {
  28:   
  29:          }
  30:   
  31:          protected void btnOK_Click(object sender, EventArgs e)
  32:          {
  33:              // 紀錄上傳路徑方便使用
  34:              string Path = "";
  35:              try
  36:              {
  37:                  // 確認 上傳檔案控制項是否有檔案
  38:                  if (FuFile.HasFile)
  39:                  {
  40:                      // 檔名使用亂碼來命名 (可用可不用)
  41:                      string filename = Guid.NewGuid().ToString();
  42:                      // 紀錄路徑
  43:                      Path = Server.MapPath(@"Upload/" + filename);
  44:                      // 把上傳的檔案儲存在伺服器內
  45:                      FuFile.SaveAs(Path);
  46:   
  47:                      if (this.xlApp == null)
  48:                      {
  49:                          this.xlApp = new Microsoft.Office.Interop.Excel.Application();
  50:                      }
  51:   
  52:                      // 打開上傳到伺服器的檔案
  53:                      this.xlApp.Workbooks.Open(Path, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
  54:                      this.wb = xlApp.Workbooks[1]; // 第一個Workbook
  55:                      this.wb.Save();
  56:   
  57:                      // 從第一個工作表讀資料
  58:                      SaveOrInsertSheet(Path, (Worksheet)xlApp.Worksheets[1]);
  59:   
  60:                      // 顯示訊息
  61:                      ClientScript.RegisterClientScriptBlock(this.GetType(), "匯入完成", "<script>alert('匯入完成');</script>");
  62:                  }
  63:              }
  64:              catch (Exception ex)
  65:              {
  66:                  throw ex; // 拋出錯誤
  67:              }
  68:              finally // 最後一定執行
  69:              {
  70:                  // 關閉 Excel 程式
  71:                  xlApp.Workbooks.Close();
  72:                  xlApp.Quit();
  73:                  try
  74:                  {
  75:                      // 刪除 Windows 工作管理員中的 Excel.exe 處理緒
  76:                      System.Runtime.InteropServices.Marshal.ReleaseComObject(this.xlApp);
  77:                      System.Runtime.InteropServices.Marshal.ReleaseComObject(this.ws);
  78:                      System.Runtime.InteropServices.Marshal.ReleaseComObject(this.aRange);
  79:                  }
  80:                  catch { }
  81:                  this.xlApp = null;
  82:                  this.wb = null;
  83:                  this.ws = null;
  84:                  this.aRange = null;
  85:   
  86:                  // 刪除 伺服器上的 Excel 檔
  87:                  System.IO.File.Delete(Path);
  88:   
  89:                  // 回收記憶體
  90:                  GC.Collect();
  91:              }
  92:          }
  93:   
  94:          private void SaveOrInsertSheet(string excel_filename, Worksheet ws)
  95:          {
  96:              // 要開始讀取的起始列(微軟工作列是從1開始算)
  97:              int rowIndex = 1;
  98:   
  99:              // 取得一列的範圍 (A 欄位 到 C欄位)
 100:              // 在這裡麻煩的地方是 只要多加一個欄位 (例如D) 下面的取值就要多加一個 Cell
 101:              this.aRange = ws.get_Range("A" + rowIndex.ToString(), "C" + rowIndex.ToString());
 102:   
 103:              // 建立一個讀取 Excel匯入的表格
 104:              System.Data.DataTable dt = new System.Data.DataTable();
 105:   
 106:              // 自訂資料欄位
 107:              dt.Columns.Add("值一");
 108:              dt.Columns.Add("值二");
 109:              dt.Columns.Add("值三");
 110:   
 111:              // 判斷Row範圍裡第一格有值的話,迴圈就往下跑
 112:              while (((object[,])this.aRange.Value2)[1, 1] != null)//用this.aRange.Cells[1, 1]來取值的方式似乎會造成無窮迴圈?
 113:              {
 114:                  // 範圍裡第一格的值
 115:                  string cell1 = ((object[,])this.aRange.Value2)[1, 1] != null ? ((object[,])this.aRange.Value2)[1, 1].ToString() : "";
 116:   
 117:                  // 範圍裡第二格的值
 118:                  string cell2 = ((object[,])this.aRange.Value2)[1, 2] != null ? ((object[,])this.aRange.Value2)[1, 2].ToString() : "";
 119:   
 120:                  // 範圍裡第三格的值
 121:                  string cell3 = ((object[,])this.aRange.Value2)[1, 3] != null ? ((object[,])this.aRange.Value2)[1, 3].ToString() : "";
 122:   
 123:                  // 新增表格內的資料行
 124:                  System.Data.DataRow dr = dt.NewRow();
 125:   
 126:                  // 第一格資料
 127:                  dr[0] = cell1;
 128:                  // 第二格資料
 129:                  dr[1] = cell2;
 130:                  // 第三格資料
 131:                  dr[2] = cell3;
 132:   
 133:                  // 加入到表格內
 134:                  dt.Rows.Add(dr);
 135:   
 136:                  //往下抓一列 Excel 範圍
 137:                  rowIndex++;
 138:                  this.aRange = ws.get_Range("A" + rowIndex.ToString(), "C" + rowIndex.ToString());
 139:              }
 140:   
 141:              // 連結表格的資料到 GridView內
 142:              GridView1.DataSource = dt;
 143:              // 並繫結資料
 144:              GridView1.DataBind();
 145:          }
 146:      }
 147:  }

程式下載點

2014年1月24日 星期五

[C#]如何達成全域變數

當時是專題的夥伴所提出來的問題,他發現了 C# 無法直接在最外層的地方使用全域變數
無解之下就去上網找了問題,之後找到了這一篇

小歐ou | 菜鳥自救會-[C#]如何達成全域變數的功能

才知道原來C# 沒有宣告全域變數的方式...