顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2018年3月15日 星期四

ASP.Net 對於從 Url 傳入 BIG5 中文的處理方法

今天同事遇到一個問題,他跟某便利商店對接挑選門市,結果對方回呼時,傳入的中文是 BIG5 的,問我要怎麼處理。

由於 Request["param_name"] 是已經「壞掉」的資料,所以得從 Request.RowUrl 下手。

經過一番搜尋,得到的結果是下面這一段程式,用指定的 Encoding 來解碼 Request.RowUrl,再用 HttpUtility.ParseQueryString 拆解成 NameValueCollection

var request = HttpUtility.ParseQueryString(
    HttpUtility.UrlDecode(
        Request.RawUrl,
        Encoding.GetEncoding("big5")));

這樣 request["param_name"] 就得到正確編碼的內容了

特記於此,以備日後查看。

2017年2月11日 星期六

於 .Net 4.5 使用 Crystal Report 的注意事項

最近接了一個定時抓資料產生報表的案子,想說應該很容易,沒想到卻因為 Crystal Report 的問題卡關了一整天

症狀是這樣的:服務一啟動就發生 1067 錯誤

2017-02-11_164847

看事件檢視器中的錯誤訊息是 System.IO.FileNotFoundException,但是卻不知道是哪個檔案找不到

2017-02-11_165040

卡了好幾個小時之後,轉個方向,改成用 Console 程式來產生報表,結果一跑就看到問題發生的原因了,是找不到這個檔案 "C:\Program Files (x86)\SAP BusinessObjects\Crystal Reports for .NET Framework 4.0\Common\SAP BusinessObjects Enterprise XI 4.0\win32_x86\dotnet1\crdb_adoplus.dll"

可是根本就沒有這個目錄,怎麼可能找得到檔案呢?

2017-02-11_165541

把這個路徑拿去 google,一搜馬上就有結果了,原來要在 App.config 的 startup 節加上 useLegacyV2RuntimeActivationPolicy="true" 這個屬性。

也就是把
<startup>
改成
<startup useLegacyV2RuntimeActivationPolicy="true">

改好之後,重新建置,執行,果然正常了。
為免遺忘,特記述於此。

2015年5月12日 星期二

用 ZXing 製作帶有中文的 QRCode

ZXing 是一個一維/二維條碼製作與識別的 library,計畫首頁在 https://github.com/zxing
本文要說的是如何製作帶有中文的 QRCode。不用囉唆了,直接看 code

using ZXing;
using ZXing.Common;
using ZXing.QrCode;
using ZXing.QrCode.Internal;

IBarcodeWriter writer = new BarcodeWriter()
{
    Format = BarcodeFormat.QR_CODE,
    Options = new QrCodeEncodingOptions()
    {
        ErrorCorrection = ErrorCorrectionLevel.M,
        Margin = 0,
        Width = 150,
        Height = 150,
        CharacterSet = "UTF-8"   // 少了這一行中文就亂碼了
    }
};

Bitmap bm =
    writer.Write(“腦殘賤貓的備忘錄 http://maolaoda.blogspot.tw/”);


這樣就得到了一個 QRCode 圖片

image

簡單吧!

2013年6月10日 星期一

ASP.Net 隱藏 RadioButtonList 裡的項目

ASP.Net 的 RadioButtonList 是一個蠻好用的控制項,用了他就不用拉好幾個 RadioButton 了。不過有一個困擾的地方就是他的 Item 並沒有 Visible 的屬性,使得有時想要隱藏某些項目時感覺有些困擾

其實,沒有 Visible 屬性也沒有關係,他有 Arrtibutes 屬性可以用,只要用
RadioButtonList1.Items[0].Attributes.Add("style", "display:none");
或是
RadioButtonList1.Items[0].Attributes["style"] = "display:none";
就可以隱藏第 0 個 item 了

提供給大家參考

2012年3月21日 星期三

ASP.Net 要透過加入 AD 的 ExchangeServer 發郵件的方法

1. 讓 ASP.Net 信任 ExchangeServer 的自訂憑證

在 Global.asax.cs 裡面的 Application_Start 事件加入以下這行:

ServicePointManager.ServerCertificateValidationCallback += 
    new RemoteCertificateValidationCallback(ValidateServerCertificate);

以及在 Global.asax.cs 加入這個靜態方法

public static bool ValidateServerCertificate(Object sender, 
    X509Certificate certificate, X509Chain chain, 
    SslPolicyErrors sslPolicyErrors)
{
    return true;
}

using 要加入

using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

2. 發郵件時程式

SmtpClient sc = new SmtpClient();
sc.Credentials = CredentialCache.DefaultNetworkCredentials;
sc.EnableSsl = true;
sc.Send(mm);    // mm 是 MailMessage

3. 在 web.config 中設定好

<system.net>
    <mailSettings>
        <smtp from="寄信人信箱" deliveryMethod="Network">
            <network host="郵件主機"
                port="埠號"
                userName="登入帳號"
                password="登入密碼"
                defaultCredentials="true" />
        </smtp>
    </mailSettings>
</system.net>

4. 將 IIS 的應用程式集區設定為「整合式」

2011年10月9日 星期日

用 NPOI 在 Excel 工作表中畫斜線

程式碼如下:
using NPOI;
using NPOI.SS.UserModel;
using NPOI.HSSF.UserModel;

……

// 於工作表上建立 HSSFPatriarch,注意!一張工作表只可以建立一個 HSSFPatriarch
HSSFPatriarch p = sheet1.CreateDrawingPatriarch() as HSSFPatriarch;

// new HSSFClientAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2) // 就是從 (col1, row1) 儲存格的 (dx1, dy1) 點 // 到 (col2, row2) 儲存格的 (dx2, dy2) 點建立一個繪圖物件的涵蓋範圍 HSSFClientAnchor a = new HSSFClientAnchor(0, 0, 0, 0, 0, 0, 1, 1); // 建立一個 HSSFSimpleShape 繪圖物件,範圍是 a,物件會充滿整個範圍 HSSFSimpleShape s = p.CreateSimpleShape(a); s.ShapeType = HSSFSimpleShape.OBJECT_TYPE_LINE; // 設定線條類型為線條 s.LineStyle = HSSFSimpleShape.LINESTYLE_SOLID; // 設定為實線 s.LineWidth = 1; // 限定線條寬度為 1

2010年11月7日 星期日

ASP.Net GridView 的自訂資料繫結

在論壇上,常常看到有網友提出這樣的問題:如果資料值是 Y/N,要顯示 是/否 在 GridView 上,要如何做?
這個問題有幾種解法

第一種:使用 GridView.RowDataBound 事件,搭配 TemplateField

這種方法是大部分的書上會介紹的方法

RowDataBound 事件,會傳入一個型別為 GridViewRowEventArgs 的參數 e
e.Row 指的是 GridView 剛剛做完資料繫結的列
e.Row.DataItem 指的是用來做這個列的資料繫結的資料來源,型別是 object
如果以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 實際上是一個 DataRowView
所以,如果以 DataTable 或是 DataSet 做資料來源,(e.Row.DataItem as DataRowView).Row["欄位名稱"] 可以取得欄位的資料值

接下來,就是「數格子」,要知道你的 TemplateField 是第幾欄,還要知道要做自訂資料繫結的控制項是 ItemTemplate 的第幾個控制項


(e.Row.Cells[欄索引].Controls[控制項索引] as 控制項型別).Text =
  (e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()

或是要知道自訂資料繫結的控制項的 ID

(e.Row.Cells[欄索引].FindControl("控制項ID") as 控制項型別).Text =
  (e.Row.DataItem as DataRowView).Row["欄位名稱"].ToString()

這種方法的缺點是
  1. 如果在這個TemplateField 之前,加入或是刪掉了其他欄,或是修改了 TemplateField 的 ItemTemplate,事件處理都得修改
  2. 如果不是以 DataTable 或是 DataSet 做資料來源,e.Row.DataItem 事實上是什麼型別?

不確定因素太多,既麻煩又複雜!強烈不建議使用這個方法

第二種:使用單純自訂資料繫結,搭配 TemplateField
這種方法直接在 TemplateField 的 ItemTemplate 中放置一個 Label,並設置 Text 屬性的資料繫結為

Text='<%# Eval("欄位名稱").ToString() == "Y" ? "是" : (Eval("欄位名稱").ToString() == "N" ? "否" : "") %>'
Text='<%# Eval("欄位名稱", "{0}") == "Y" ? "是" : (Eval("欄位名稱", "{0}") == "N" ? "否" : "") %>'

簡單明瞭,只是判斷是寫在 .aspx 裡面,而且當資料值是 DbNull 的時候會發生錯誤,如果還要加上判斷是否為 DbNull 的語法就更複雜了
因此,此方法建議使用於簡單判斷以及資料欄位不允許 null 的狀況
PS: Eval("欄位名稱") 與 Eval("欄位名稱", "{0}") 的不同點在於前者回傳的是 Object,後者回傳的是 String

第三種:使用自訂資料繫結方法,搭配 TemplateField
跟第二種方法類似,只是將 Label 的 Text 屬性的資料繫結改為呼叫一個自訂方法 (必須為 public 或 protected 方法)

Text='<%# YesOrNo(Eval("欄位名稱")) %>'

並撰寫後端程式碼如下:
protected string YesOrNo(object o)
{
  string s = o == DbNull.Value ? "" : Convert.ToString(o);
  return s == "Y" ? "是" : (s == "N" ? "否" : "");
}
這樣的好處是

  1. 不用數格子
  2. 沒有複雜的資料繫結語法
  3. 無論從何種資料來源做資料繫結,都可以適用
  4. 可檢查資料是否為 DbNull
提供給大家做參考

2010年9月8日 星期三

多螢幕環境下,指定螢幕顯示畫面 (C#)

private void ChangeScreen(Form aForm, int screenId)  
{   
  // 先將 Form 設定為 Normal   
  aForm.WindowState = FormWindowState.Normal;   
  
  // 改 Location   
  aForm.StartPosition = FormStartPosition.Manual;   
  if (screenId < Screen.AllScreens.Length)   
  {   
    aForm.Location = Screen.AllScreens[screenId].WorkingArea.Location;   
  }   
  
  // 最後設定成 Maximized   
  aForm.WindowState = FormWindowState.Maximized;   
}

2009年10月30日 星期五

取得物件的私有欄位、呼叫已經綁定在物件上的事件

要 using System.Reflection、System.ComponentModel、System.Text 三個命名空間
public string ListFields(Type type)
{
  StringBuilder sb = new StringBuilder();
  FieldInfo[] fieldInfos = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
  sb.Append(@"<table border='1' cellpadding='3' cellspacing='0'><tr><th>Field Name</th>
              <th>Type</th><th>Static</th></tr>");
  foreach (FieldInfo fInfo in fieldInfos)
  {
    sb.AppendFormat("<tr><td>{0:s}</td><td>{1:s}</td><td>{2:s}</td></tr>",
      fInfo.Name, fInfo.FieldType.FullName, fInfo.IsStatic ? "Yes" : "No");
  }
  sb.Append("</table>");
  return sb.ToString();
}
這樣就可以把 type 裡面定義的私有欄位,用 Table 的方式顯示出來
如果私有欄位定義在 base class 中,則傳入 obj.GetType().BaseType
執行範例一: 
System.Web.UI.WebControls.FormView() FormView1 = new System.Web.UI.WebControls.FormView();
ListFields(FormView1.GetType());
Field Name Type Static
EventPageIndexChanged System.Object Yes
EventPageIndexChanging System.Object Yes
EventItemCommand System.Object Yes
EventItemCreated System.Object Yes
EventItemDeleted System.Object Yes
EventItemDeleting System.Object Yes
EventItemInserting System.Object Yes
EventItemInserted System.Object Yes
EventItemUpdating System.Object Yes
EventItemUpdated System.Object Yes
EventModeChanged System.Object Yes
EventModeChanging System.Object Yes
執行範例二: 
System.Web.UI.WebControls.DropDownList DopDownList1 = new System.Web.UI.WebControls.DropDownList();
ListFields(DropDownList1.GetType());
Field Name Type Static

??怎麼沒有東西??
那麼改用 ListFields(dropDownList1.GetType().BaseType) 試看看
Field Name Type Static
EventSelectedIndexChanged System.Object Yes
EventTextChanged System.Object Yes
果然有了!
拿到這些私有欄位的名稱有什麼用?各位發覺到了嗎,這些私有欄位都是以 Event 開頭的,也就是說這些是用來儲存 Delegate 的私有變數
接下來,就可以利用以下的程式,來呼叫「已經綁定在物件上的事件處理函式」
public void InvokeEvent(object obj, Type type, string eventName, EventArgs e)
{  
  PropertyInfo propertyInfo = (type.GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic));
  EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(obj, null);
  FieldInfo fieldInfo = type.GetField(eventName, BindingFlags.Static | BindingFlags.NonPublic);
  Delegate[] dels = eventHandlerList[fieldInfo.GetValue(null)].GetInvocationList();
  foreach (Delegate d in dels)
  {  
    d.Method.Invoke(d.Target, new object[] { obj, e });
  }
}
呼叫範例:
InvokeEvent(DropDownList1, DropDownList1.GetType().BaseType, "EventSelectedIndexChanged", e);

2008年7月4日 星期五

詐砲的自訂公式

假如客戶要求你,某一個計算公式可以讓他自由設定,你想要怎麼做?
例如:加班費計算
有些人想要 ROUND(時薪 * 加班費比例) * 時數
有些人想要 FLOOR(時薪 * 加班費比例) * 時數
有些人想要 ROUND(時薪 * 加班費比例 * 時數)
有些人想要 FLOOR(時薪 * 加班費比例 * 時數)

於是就有程式人員這樣寫啦
switch(計算方式)
{
case "1" :
 加班費 = ROUND(時薪 * 加班費比例) * 時數;
 break;
case "2" :
 加班費 = FLOOR(時薪 * 加班費比例) * 時數;
 break;
case "3" :
 加班費 = ROUND(時薪 * 加班費比例 * 時數);
 break;
case "4" :
 加班費 = FLOOR(時薪 * 加班費比例 * 時數);
 break;
}
第五種狀況出現時怎麼辦?改程式?寫程式一定要這樣歹命嗎?
來!我有一個詐砲方法給大家參考
就是請資料庫伺服器幫你算!
以 SQL Server 為例子

SELECT ROUND(@時薪 * @加班費比例, 0) * @時數

只要把 @時薪、@加班費比例、@時數 三個參數丟進去,就有計算結果啦
所以呢,「ROUND(@時薪 * @加班費比例, 0) * @時數」這一串文字就可以變成「加班費計算公式」的設定
反正加班費再怎麼算,都脫離不了時薪、加班費比例、時數三個參數

我覺得這個方法相當不錯,提供您參考喔~~

2008年6月17日 星期二

C# 使用 ADOX 建立新 Table

有時,需要把資料匯出到 MDB 裡面,但是在 ADO.Net 中沒有建立 MDB 以及在 MDB 中建立 Table 的功能 (create table 的 SQL 敘述除外)。
所以,有必要撰寫這樣的工具程式,以便於後續方便使用

使用 ADO 以及 ADOX 之前,要加入兩個 COM 的參考
  1. C:\Program Files\Common Files\System\ado\msado15.dll (ADODB)
  2. C:\Program Files\Common Files\System\ado\msadox.dll (ADOX)
這兩個 COM 加進來之後,命名空間如括弧內所示
接下來,撰寫程式如下

/// <summary>
/// 建立 MDB 資料庫以及資料表
/// </summary>
public class MDBCreate
{
  private ADOX.CatalogClass catalog = new ADOX.CatalogClass();
  private ADODB.Connection connection = new ADODB.ConnectionClass();
  private string createConnStr =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source={0}";
  private string _fileName = "";

  /// <summary>
  /// MDB 檔案名稱
  /// </summary>
  public string FileName
  {
    get
    {
      return _fileName;
    }
    set
    {
      _fileName = value;

    }
  }

  /// <summary>
  /// 建立新的 MDB 資料庫
  /// </summary>
  /// <param name="deleteIfExist">是否刪除現有的</param>
  /// <returns>是否建立成功</returns>
  public bool CreateMDB(bool deleteIfExist)
  {
    try
    {
      if (deleteIfExist)
      {
        if (File.Exists(_fileName))
          File.Delete(_fileName);
      }
      catalog.Create(String.Format(createConnStr, _fileName));
      return true;
    }
    catch
    {
      return false;
    }
  }

  /// <summary>
  /// 利用 DataTable 結構,於 MDB 檔案中建立新的 Table
  /// </summary>
  /// <param name="tableName">Table 名稱</param>
  /// <param name="sourceTable">包含表格結構的 DataTable 執行個體</param>
  /// <returns>是否建立成功</returns>
  public bool CreateTable(string tableName, DataTable sourceTable)
  {
    string connStr = String.Format(createConnStr, _fileName) + ";Persist Security Info=False";
    connection.Open(connStr, "", "", 0);
    catalog.ActiveConnection = connection;

    ADOX.TableClass table = new TableClass();
    ADOX.DataTypeEnum fieldType = ADOX.DataTypeEnum.adWChar;
    int fieldLength = 0;

    table.Name = tableName;

    for (int i = 0; i < sourceTable.Columns.Count; i++)
    {
      DataColumn column = sourceTable.Columns[i];

      switch (column.DataType.FullName)
      {
        case "System.Boolean":
          fieldType = ADOX.DataTypeEnum.adBoolean;
          break;
        case "System.Byte":
          fieldType = ADOX.DataTypeEnum.adUnsignedTinyInt;
          break;
        case "System.Char":
          fieldType = ADOX.DataTypeEnum.adWChar;
          fieldLength = column.MaxLength;
          if (fieldLength == -1)
            fieldLength = 255;
          break;
        case "System.DateTime":
          fieldType = ADOX.DataTypeEnum.adDate;
          break;
        case "System.Decimal":
          fieldType = ADOX.DataTypeEnum.adCurrency;
          break;
        case "System.Double":
          fieldType = ADOX.DataTypeEnum.adDouble;
          break;
        case "System.Int16":
          fieldType = ADOX.DataTypeEnum.adSmallInt;
          break;
        case "System.Int32":
          fieldType = ADOX.DataTypeEnum.adInteger;
          break;
        case "System.Int64":
          fieldType = ADOX.DataTypeEnum.adInteger;
          break;
        case "System.SByte":
          fieldType = ADOX.DataTypeEnum.adSmallInt;
          break;
        case "System.Single":
          fieldType = ADOX.DataTypeEnum.adSingle;
          break;
        case "System.String":
          // 因為 MDB 檔的文字欄位最大長度是 255
          // 所以超過時,以 memo 欄位存放
          if (column.MaxLength > 255)
          {
            fieldType = ADOX.DataTypeEnum.adLongVarWChar;
            fieldLength = 0;
          }
          else
          {
            fieldType = ADOX.DataTypeEnum.adVarWChar;
            fieldLength = column.MaxLength;
            if (fieldLength == -1)
              fieldLength = 255;
          }
          break;
        case "System.UInt16":
          fieldType = ADOX.DataTypeEnum.adSmallInt;
          break;
        case "System.UInt32":
          fieldType = ADOX.DataTypeEnum.adInteger;
          break;
        case "System.UInt64":
          fieldType = ADOX.DataTypeEnum.adInteger;
          break;
        case "System.Byte[]":
          fieldType = ADOX.DataTypeEnum.adLongVarBinary;
          break;
      }

      // 將新增的欄位物件加入 Table 中,並設定欄位屬性為可 null
      table.Columns.Append(column.ColumnName, fieldType, fieldLength);
      table.Columns[i].Attributes = ColumnAttributesEnum.adColNullable;
    }

    try
    {
      // 將新增的 Table 物件加入 Catalog 物件,以達到建立新 Table 的目的
      catalog.Tables.Append(table);
      catalog.ActiveConnection = null;
      return true;
    }
    catch
    {
      return false;
    }
    finally
    {
      connection.Close();
    }
  }
}