2009年8月21日 星期五

網頁輸入頁面Enter鍵處理元件(KeyDownProcess Version:1.2)

function KeyDownProcess() {
//-----------------------------------------------------------
//網頁親和性輸入控制元件
//元件功能:可以讓網頁資料的輸入更親切,功能如下:
//1.按下Enter鍵自動找到下一個可輸入輸入元件
//2.按下Enter鍵自動找尋submit按鍵,如果找到則模擬Click的功能
//3.當輸入元件設定唯讀時,按下backspace鍵時,防止網頁轉址
//版本:1.2(2009.08.21)
//作者:科碩資訊有限公司
//引用本元件,請保留作者和版本資訊
//聯絡mail:cursor@cursorinfo.com.tw
//------------------------------------------------------------
var kv = 0;
var rv = false;
var isTextarea = false;
var currentId = null; //目前元件
if (document.all && typeof (document.all) == "object") {
kv = event.keyCode;
isTextarea = (event.srcElement.tagName == "TEXTAREA");
currentId = event.srcElement.id;
}
else {
kv = evt.keyCode;
isTextarea = (evt.target == "TEXTAREA");
currentId = evt.id;
}
switch (kv) {
case 8:
if (currentId.length == 0)
return false;
return !document.getElementById(currentId).readOnly;
case 13:
if (currentId.length == 0)
return false;
if (isTextarea == true) {
rv = isTextarea;
}
else {
var cts = document.all && typeof (document.all) == "object" ? document.all : document.getElementsByTagName('input');
var cid = "";
var queryBu = null;
var beginNext = false; //開始比對是否為輸入元件
var nextInput = null; //下一個輸入元件
var specialSubmitId = "textQueryBU"; //指定特例的submit id
var exceptionSubmitId = "waitting"; //指定例外的submit Id
for (ii = 0; ii < cts.length; ii++) {
if (cts[ii].id == currentId) {
beginNext = true;
continue;
}
if (beginNext == true && (cts[ii].id.indexOf(specialSubmitId) > -1 || ((cts[ii].type == "submit" || cts[ii].type == "image") && cts[ii].id.indexOf(exceptionSubmitId) == -1))) {
queryBu = cts[ii]; //找到submit元件
break;
}
else if (beginNext == true && (cts[ii].type == "text" || cts[ii].type == "textarea" || cts[ii].type == "password") && cts[ii].readOnly == false && cts[ii].style.display != "none") {
nextInput = cts[ii]; //找到下一個文字輸入元件
break;
}
}
if (null != queryBu) {
setTimeout("doClickId('" + queryBu.id + "');", 100);
rv = false;
}
else if (null != nextInput) {
try {
nextInput.focus();
} catch (Error) { return true; }
rv = false;
}
}
break;
default:
rv = true;
break;
}
return rv;
}

//實做模擬Click的功能
function doClickId(source) {
var o = document.getElementById(source);
if (document.all && typeof (document.all) == "object") //IE
o.click();
else {
var e = document.createEvent('mouseEvent');
e.initEvent('click', false, false);
o.dispatchEvent(e);
}
}
function DoRefresh() {
__doPostBack('__Page', 'postback');
}

2009年6月25日 星期四

糟糕,ASP.NET 出現'WebForm_PostBackOptions' 未被定義的錯誤

問題說明:ASP.NET應用程式執行中出現'WebForm_PostBackOptions' 未被定義的錯誤訊息,該怎麼辦?
問題分析:最近有個機會需要將MySQL的日期資料轉為MsSQL的日期資料,在未查明MySQL的日期資料型別前;直接使用long.Paser的Method將資料解析為數值後,直接new DateTime(long),結果就出現了致命性的錯誤;不但AJAX出現下面的問題:
訊息: 語法錯誤
行: 1
字元: 1
程式碼: 0
URI: http://master.cursorinfo.com.tw:7000/AideRegister/WebResource.axd?d=5-EZy3-7lrBUw0173cFa5A2&t=633813918869843750
而且,
ASP.NET應用程式執行中出現'WebForm_PostBackOptions' 未被定義的錯誤。
請教微軟技術諮詢中心沈先生後得到的解答是:
您的錯誤訊息應是頁面直接報錯,目前看來時間戳記是上周四,造成程式碼有問題,可能Web Server上的時間有誤。
沒錯,就是ASP.NET的時間戳記出現了混淆的狀態。

解決方案:
依據沈先生建議,在網路上搜尋解決方案,得到的正解是:重新安裝.NET Framework 2.0即可。
可是重新安裝.NET Framework 2.0有些步驟須注意,因此,將相關方法說明如下,提供有此需求者減少摸索的時間。

重新安裝.NET Framework 2.0步驟:
1.開起系統控制台的新增移除程式,確定已安裝的.NET Framework 2.0的版本。
2.下載該版本的可轉散發套件。
3.將該套件解壓縮在已知的路徑待用。
4.找到新增移除程式中的.NET Framework 2.0,點選這個套件後,在更新的資料中,找到『按這裡取得資源資訊』,然後在彈出的視窗中,找到『修復』按鈕。
5.點選修復按鈕後,進行修復工作。如果原安裝的解壓縮檔已刪除,系統會顯示瀏覽安裝來源的視窗,只要將檔案來源指向剛才解壓縮後的資料夾,即可進行修復工作。

後記:
1.詳查網路資源後,才知道MySQL的日期資料,是unix日期型別,只要使用FROM_UNIXTIME()的函數,就可以解析該日期資料。(MySQL支援該函數)
2.MySQL發佈了Connector元件,可以讓.NET輕鬆存取MySQL資料庫;相當不錯的元件。Thanks.

2009年6月16日 星期二

Events in ASP.NET Master and Content Pages

Master page controls Init event.

Content controls Init event.

Master page Init event.

Content page Init event.

Content page Load event.

Master page Load event.

Master page controls Load event.

Content page controls Load event.

Content page PreRender event.

Master page PreRender event.

Master page controls PreRender event.

Content page controls PreRender event.

Master page controls Unload event.

Content page controls Unload event.

Master page Unload event.

Content page Unload event.

Source Url:http://msdn.microsoft.com/en-us/library/dct97kc3.aspx

2009年4月24日 星期五

ASP.NET無接縫傳值頁面處理後續-如何重新整理來源頁面?

問題說明:
 當我們使用了無接縫傳值撰寫模式,完成Master/Detail的編修資料後,大部份的情況都需要重新整理來源頁的頁面,才能立即顯示修正後的資料。在這種情況下要如何處理?
可能方法包含:
1.使用window.opener.location.reload();
2.呼叫來源頁的重整功能。
這兩個方法中,window.opener.location.reload();會產生是否要重整的確認視窗,而且整個網頁重新進入一次,使用上比較不經濟。第二個方法可以配合AJAX把握重點,只整理需要的頁面。
個人習慣使用第二種方法。

我的作法:
 1.在來源頁上配置一個ImageButton的Control。語法如下:
 <asp:imagebutton id="refreshBU" alternatetext="頁面重整" imageurl="~/Images/refresh.png" oncommand="refreshBU_Command" runat="server">
 2.加入一個doRefresh()的javascript function(),語法如下:
 function doRefresh() { doClickId("<%=refreshBU.ClientID %>"); }
 doClickId()在ASP.NET無接縫傳值撰寫模式中已建立。
 3.撰寫refreshBU_Command事件處理機制,可能是重新Binding GridView。
 4.彈出的頁面中加入編修或處理結束後來源頁的功能呼叫。語法如下:
 <script type="text/javascript">
 function confirmSave(){
 alert('回應資料已存檔,頁面即將關閉!');
 window.opener.doRefresh();
 window.open('', '_parent', '');
 window.close();
 }
 </script> 

2009年4月20日 星期一

一個關於ASP.NET RadioButtonList 控制元件操作上的注意事項

問題說明:
在ASP.NET的環境中操作RadioButtonList 控制元件時,如果在伺服端預設SelectedIndex時;例如設定了SelectedIndex=0,當使用者於網頁上點選第一項以外的選項時,SelectedIndexChanged的事件可以正常運作,但時回點第一項選項時發現無法啟動SelectedIndexChanged的事件。
也就是說在伺服端預設的SelectedIndex後,會導致該選項沒有SelectedIndexChanged的事件。

解決方法:
必須於網頁OnLoad或OnFocus時,使用Javascript定義預設的選項,不能在伺服端預設選項。
下面是我的作法:
window.onfocus = function() {
 var ctrl = document.getElementById("<%=RadioButtonList1.ClientID%>" + "_0");
 ctrl.checked = true;
};

2009年3月27日 星期五

網頁輸入頁面Enter鍵處理元件(KeyDownProcess Version:1.1)

function KeyDownProcess() {
//-----------------------------------------------------------
//網頁親和性輸入控制元件
//元件功能:可以讓網頁資料的輸入更親切,功能如下:
//1.按下Enter鍵自動找到下一個可輸入輸入元件
//2.按下Enter鍵自動找尋submit按鍵,如果找到則模擬Click的功能
//版本:1.1(2009.03.27)
//作者:科碩資訊有限公司
//引用本元件,請保留作者和版本資訊
//聯絡mail:cursor@cursorinfo.com.tw
//------------------------------------------------------------
var kv = 0;
var rv = false;
var isTextarea = false;
var currentId = null; //目前元件
if (document.all && typeof (document.all) == "object") {
kv = event.keyCode;
isTextarea = (event.srcElement.tagName == "TEXTAREA");
currentId = event.srcElement.id;
}
else {
kv = evt.keyCode;
isTextarea = (evt.target == "TEXTAREA");
currentId = evt.id;
}
switch (kv) {
case 13:
if (currentId.length == 0)
return false;
if (isTextarea == true) {
rv = isTextarea;
}
else {
var cts = document.all && typeof (document.all) == "object" ? document.all : document.getElementsByTagName('input');
var cid = "";
var queryBu = null;
var beginNext = false; //開始比對是否為輸入元件
var nextInput = null; //下一個輸入元件
var specialSubmitId = "logonBU"; //指定特例的submit id
var exceptionSubmitId = "waitting"; //指定例外的submit Id
for (ii = 0; ii < cts.length; ii++) {
if (cts[ii].id == currentId) {
beginNext = true;
continue;
}
if (beginNext == true && (cts[ii].id.indexOf(specialSubmitId) > -1 || (cts[ii].type == "submit" && cts[ii].id.indexOf(exceptionSubmitId) == -1))) {
queryBu = cts[ii]; //找到submit元件
break;
}
else if (beginNext == true && (cts[ii].type == "text" || cts[ii].type == "textarea" || cts[ii].type == "password") && cts[ii].readOnly == false && cts[ii].style.display != "none") {
nextInput = cts[ii]; //找到下一個文字輸入元件
break;
}
}
if (null != queryBu) {
setTimeout("doClickId('" + queryBu.id + "');", 100);
rv = false;
}
else if (null != nextInput) {
try {
nextInput.focus();
} catch (Error) { return true; }
rv = false;
}
}
break;
default:
rv = true;
break;
}
return rv;
}

//實做模擬Click的功能
function doClickId(source) {
var o=document.getElementById(source);
if (document.all && typeof (document.all) == "object") //IE
o.click();
else {
var e = document.createEvent('mouseEvent');
e.initEvent('click', false, false);
o.dispatchEvent(e);
}
}

2009年3月16日 星期一

ADSI技術文章-使用WinNT Provider取得User的Groups

public Dictionary GetWinNtUserGroups(string userName, string uName, string pwd)
{
Dictionary rv = new Dictionary();
string adsPath = string.Format("WinNT://{0}/{1},user", Environment.MachineName, userName);
if (DirectoryEntry.Exists(adsPath) == true)
{
DirectoryEntry user = new DirectoryEntry(adsPath, uName, pwd);
IADsGroup ig;
//叫用 Group 的 Members
object groups = user.Invoke("Groups", null);
DirectoryEntry gEntry;
foreach (object go in (IEnumerable)groups)
{
gEntry = new DirectoryEntry(go);
if (gEntry.SchemaClassName.ToLower() == "group")
{
ig = (IADsGroup)gEntry.NativeObject;
rv.Add(ig.Name, ig.Description);
}
}
}
return rv;
}

ADSI技術文章-使用WinNT Provider取得User的Groups

問題說明:
如果我們想使用WinNT Provider,取得user的群組清單,應該如何做呢?
下面範例會傳回一組群組名稱和描述的Dictionary資料:

public Dictionary GetWinNtUserGroups(string userName, string uName, string pwd)
{
Dictionary rv = new Dictionary();
string adsPath = string.Format("WinNT://{0}/{1},user", Environment.MachineName, userName);
if (DirectoryEntry.Exists(adsPath) == true)
{
DirectoryEntry user = new DirectoryEntry(adsPath, uName, pwd);
IADsGroup ig;
//叫用 User 的 Groups
object groups = user.Invoke("Groups", null);
DirectoryEntry gEntry;
foreach (object go in (IEnumerable)groups)
{
gEntry = new DirectoryEntry(go);
if (gEntry.SchemaClassName.ToLower() == "group")
{
ig = (IADsGroup)gEntry.NativeObject;
rv.Add(ig.Name, ig.Description);
}
}
}
return rv;
}
*使用IADsGroup的COM介面,可以輕鬆取得group的屬性。
*使用IADsGroup的COM介面,須參考ActiveDs.dll。

2009年3月15日 星期日

如何利用Web 服務描述語言工具(Wsdl.exe)產生Web Service的類別?

問題說明:
.NET Framework 提供了Web 服務描述語言工具Wsdl.exe,最主要的用途是: 從WSDL 合約檔案、XSD 結構描述 (Schema) 和 .discomap 探索文件產生 XML Web Service 和 XML Web Service 用戶端的程式碼。其中產生XML Web Service 用戶端的程式碼,就是只產生Web Service的用戶端類別,做為應用程式直接引用的來源。
使用 Wsdl.exe 建立 Proxy 類別時,請參閱Microsoft MSDN說明。
網址:Web 服務描述語言工具 (Wsdl.exe)

Wsdl.exe存放位址:C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin

建立Web Service Proxy類別,最直接的方法如下:
1.假設目前有一個Web Service的網址為:http://ws.interfax.net/admin.asmx
2.使用下列語法可以產生Web Service Proxy類別,檔名為admin.cs:
 wsdl /out:admin.cs http://ws.interfax.net/admin.asmx?wsdl
3.將該類別加入應用程式專案,就可以直接呼叫Web Service的Method 或Properties。應用程式不必另行加入Web參考。

另外,您可以使用 Web 服務探索工具 (Disco.exe) 來取得 XML Web Service 的探索文件。由這個工具所產生的 .discomap、.disco、.wsdl 和 .xsd 檔案可以用作 Wsdl.exe 的輸入。

2009年3月13日 星期五

ADSI相關雜記

*Windows 2008 Server安裝Active Directory時,提供AdsiEdit.msc服務。使用該服務可以完整瀏覽與管理,AD的物件與物件屬性。

*Windows 2003 server使用ADSI WinNT Provider 新增、異動物件時,須設定:
同步處理目錄服務之帳號(本機安全性設定-使用者權利指派-同步處理目錄服務的資料)

2009年3月9日 星期一

Web Application輸入頁面按下Enter鍵時,如何模擬Click功能?續2

問題說明:
攔截Enter鍵,模擬Click功能的Java Script 程式,經過統整後發展成:
在資料輸入頁面,可以自動偵測Enter鍵,處理到下筆資料區或送出資料的功能。

請參閱下面程式碼:

function KeyDownProcess() {
var kv = 0;
var rv = false;
var isTextarea = false;
var currentId=null;//目前元件
if (document.all && typeof (document.all) == "object") {
kv = event.keyCode;
isTextarea = (event.srcElement.tagName == "TEXTAREA");
currentId = event.srcElement.id;
}
else {
kv = evt.keyCode;
isTextarea = (evt.target == "TEXTAREA");
currentId=evt.id;
}
switch (kv) {
case 13:
if (currentId.length == 0)
return false;
if (isTextarea == true) {
rv = isTextarea;
}
else {
var cts = document.all && typeof (document.all) == "object" ? document.all.tags("input") : document.getElementsByTagName('input');
var cid = "";
var queryBu = null;
var beginNext = false; //開始比對是否為輸入元件
var nextInput = null; //下一個輸入元件
for (ii = 0; ii < cts.length; ii++) {
if (beginNext == true && (cts[ii].type == "text") && cts[ii].readOnly == false) {
nextInput = cts[ii]; //找到下一個文字輸入元件
break;
}
if (cts[ii].id == currentId) {
beginNext = true;
}

if (cts[ii].type == "submit" && beginNext == true) {
queryBu = cts[ii]; //找到submit元件
break;
}
}
if (null != queryBu) {
setTimeout("doClick('" + queryBu.id + "');", 100);
rv = false;
}
else if (null != nextInput) {
nextInput.focus();
rv = false;
}
}
break;
default:
rv = true;
break;
}
return rv;
}

//實做模擬Click的功能
function doClick(o) {
if (document.all && typeof (document.all) == "object") //IE
o.click();
else {
var e = document.createEvent('mouseEvent');
e.initEvent('click', false, false);
o.dispatchEvent(e);
}
}

*以上程式碼,適用於使用Input Buttom Submit type的資料後送模式;如果使用Input Button Image type,則需要修改判斷的type 為image。

後記:
如有任何建議或改善意見,歡迎隨時來函指正或討論。Thanks.

2009年3月1日 星期日

ADSI技術文章-使用WinNT Provider取得Group的Users

問題說明:
如果我們想使用WinNT Provider,透過群組名稱取得所有的成員,應該如何做呢?
下面範例會傳回一組帳號和FullName的Dictionary資料:

public Dictionary GetWinNtGroupUsers(string groupName, string uName, string pwd)
{
Dictionary rv = new Dictionary();
string adsPath = string.Format("WinNT://{0}/{1},group", Environment.MachineName, groupName);
if (DirectoryEntry.Exists(adsPath) == true)
{
DirectoryEntry group = new DirectoryEntry(adsPath, uName, pwd);
IADsUser iu;
//叫用 Group 的 Members
object members = group.Invoke("Members", null);
DirectoryEntry mEntry;
foreach (object mb in (IEnumerable)members)
{
mEntry = new DirectoryEntry(mb);
if (mEntry.SchemaClassName.ToLower() == "user")
{
iu = (IADsUser)mEntry.NativeObject;
rv.Add(iu.Name, iu.FullName);
}
}
}
return rv;
}
*使用IADsUser的COM介面,可以輕鬆取得User的屬性。
*使用IADsUser的COM介面須加入ActiveDs.dll參考項。

2009年2月28日 星期六

在ASP.NET的Web使用者控制項中,如何利用delegate傳出資料?

問題說明:
一般程式開發過程Reuse的技術是必要的,透過Reuse的做法可精簡系統程式碼;更可以減少程式維護的複雜度。ASP.NET的Web使用者控制項就是基於Reuse的觀念而建立的機制。Web使用者控制項的Reuse可以分為兩種類型:一是不同頁面直接重覆引用、二是透過Property的設定更改控制項元件頁面重覆使用。這兩種類型都有可能需要將處理完成的資料外送給父頁。本文將說明作者如何透過delegate的機制,建立Web使用者控制項專用的事件,傳出選取或處理完成的資料;讓資料選取或處理頁面和後續處理機制分離。如此可以大大的提高此使用者控制項的Reuse功能,傳出的資料也可以有不同的處理彈性。

本文將以資料選取的Web使用者控制項為Reuse元件,在該控制項中包含了一個GridView元件和一個Button元件,GridView中除了資料欄位外,外加一個CheckBox,做為使用者選取該筆資料與否的標誌。
使用者點選資料後,假設需要外送的資料有兩個屬性~:
1.資料來源:string SourceName
2.選取的資料清單:Dictionary SelectedInfo

我的做法如下:

1.宣告一個delegate 命名為:ButtonSelectedClick
2.建立一個EventArgs 命名為:ClickEvenArgsDictionary
程式碼如下:
public delegate void ButtonSelectedClick(object sender, ClickEvenArgsDictionary e);
public class ClickEvenArgsDictionary : EventArgs
{
public Dictionary SelectedInfo { get; set; }
public string SourceName { get; set; }
public ClickEvenArgsDictionary(Dictionary selectedInfo,string sourceName)
{
this.SelectedInfo = selectedInfo;
this.SourceName = sourceName;
}

}

3.在資料處理的頁面加入ButtonSelectedClick的event 命名為 ucSelectedClick
程式碼如下:
public event ButtonSelectedClick ucSelectedClick;

4.在資料處理頁面的Button Click事件中處理deletegate的外傳事件
程式碼如下:
string sourceName="source name";
Dictionary selected = new Dictionary();
...
...
選取資料的處理程式碼
...
ClickEvenArgsDictionary ce = new ClickEvenArgsDictionary(selected,sourceName);
if (ucSelectedClick != null)
this.buttonClick(this, ce);

5.在引用此控制項頁面中Page_Load()中設定資料處理頁面的事件,假設此資料處理頁面的ID:UserDataBrows1
程式碼如下:
UserDataBrows1.ucSelectedClick +=new ButtonSelectedClick(UserDataBrows1_ucSelectedClick);

6.在事件捕捉區完成資料的處理或存檔
程式碼如下:
void UserDataBrows1_ucSelectedClick(object sender, ClickEvenArgsDictionary e)
{
  //在此事件捕捉區中可以取得:e.SourceName 和 e.SelectedInfo
}

完成上面六個處理步驟,就可以輕鬆的捕捉到使用者控制項傳出來的資料,讓控制項和資料處理頁面完全分離。

後記:
1.這是delegate功能的另一種用法,希望能幫助有此需求的系統開發者。
2.Delegates in C# are like functions pointers in C/C++.
3.如有任何建議或改進意見,歡迎隨時來函指正或討論。Thanks.

2009年2月27日 星期五

ADSI技術文章-使用LDAP Provider取得Group的Users

問題說明:
如果我們想使用LDAP Provider,透過群組名稱取得所有的成員,應該如何做呢?
下面範例會傳回一組帳號和FullName的Dictionary資料:

public static Dictionary GetLDApGroupUsers(string ldapPath,string groupName,string uName,string pwd)
{
Dictionary rv=new Dictionary();
DirectoryEntry domain = new DirectoryEntry(ldapPath , uName, pwd);
DirectorySearcher search = new DirectorySearcher(domain);
search.SearchScope = SearchScope.Subtree;
//搜尋條件
search.Filter = string.Format("(&(objectclass=Group)(cn={0}))",groupName);
SearchResult result = search.FindOne();
if (result != null)
{
DirectoryEntry gEntry = result.GetDirectoryEntry();
DirectoryEntry mEntry;
IADsUser iu;
DataRow dr;
//叫用 Group 的 Members
object members = gEntry.Invoke("Members", null);
foreach (object mb in (IEnumerable)members)
{
mEntry = new DirectoryEntry(mb);
if (mEntry.SchemaClassName == "user")
{
iu = (IADsUser)mEntry.NativeObject;
rv.Add(iu.Name.Split('=')[1],iu.FullName));
}
}
}
return rv;
}
*使用IADsUser的COM介面,可以輕鬆取得User的屬性。

2009年2月26日 星期四

Web Application輸入頁面按下Enter鍵時,如何模擬Click功能?續1

問題說明:
當使用者在網頁頁面習慣性按下Enter鍵時,我們在第一篇文章已經說明了,如何模擬滑鼠Click的功能。但是問題來了,如果網頁頁面上包含了TEXTAREA(ASP.NET的TextBox MultiLine)時,當使用者在此元件中輸入資料時,按下了Enter鍵,系統也啟動滑鼠Click的功能,應該會讓使用者嚇一跳;因為此時使用者應該是希望換下一行,而不是將資料送出,所以面對有TEXTAREA輸入元件的網頁時,就必須調整按鍵處理機制的程式碼!

我的做法如下:

//啟動網頁攔截按鍵機制
window.onload =function(){
document.onkeydown=KeyDownProcess;
};

function KeyDownProcess() {
var kv = 0;
var rv = false;
var isTextarea = false;
if (document.all && typeof (document.all) == "object") {
kv = event.keyCode;
isTextarea = (event.srcElement.tagName == "TEXTAREA");
}
else {
kv = evt.keyCode;
isTextarea = (evt.target == "TEXTAREA");
}
switch (kv) {
case 13:
if (isTextarea ==true) {
rv = isTextarea;
}
else {
var cts = document.all && typeof (document.all) == "object" ? document.all.tags("input") : document.getElementsByTagName('input');
var cid = "";
var queryBu = null;
for (ii = 0; ii < cts.length; ii++) {
if (cts[ii].type == "submit" && cts[ii].id.indexOf("loginBU") > -1) {
queryBu = cts[ii];
break;
}
}
if (null != queryBu) {
doClick(queryBu);
rv = false;
}
}
break;
default:
rv = true;
break;
}
return rv;
}
//實做模擬Click的功能
function doClick(o) {
if (document.all && typeof (document.all) == "object") //IE
o.click();
else {
var e = document.createEvent('mouseEvent');
e.initEvent('click', true, true);
o.dispatchEvent(e);
}
}
*以上程式碼,適用於使用Input Buttom Submit type的資料後送模式;如果使用Input Button Image type,則需要修改判斷的type 為image。

後記:
如有任何建議或改善意見,歡迎隨時來函指正或討論。Thanks.

2009年2月25日 星期三

Web Application輸入頁面按下Enter鍵時,如何模擬Click功能?

問題說明:
在網頁上如果包含資料輸入元件和『送出』的按鈕時,當使用者輸入完資料後,會習慣性的按下Enter鍵,想將資料送出存檔,而一般網頁基本設定是需要按下『送出』這個按鈕,才開始檢驗資料或後送資料;因此,如果想讓使用者按下Enter鍵就可以達到『送出』的功能,需要透過Java Script達成來模擬object Click的功能。
如何達到上面的需求呢?個人試以登入頁面為例,將相關的Java Script程式碼說明如下:

有關登入頁面的元件部署和程式不在這裡說明,一般說來登入頁面應該會有一顆按鈕是執行資料後送的功能,這個元件的ID就假設為:loginBU。
假設上面的條件式成立的,下面的程式碼就可以完成:使用者按下Enter鍵時,自動模擬 loginBU Click的功能:

//啟動網頁攔截按鍵機制
document.onkeydown = KeyDownProcess;

//使用者如果按下Enter鍵時,模擬Click功能
function KeyDownProcess(){
var kv = 0;
if (document.all&& typeof (document.all) == "object") //IE
kv = event.keyCode;
else
kv = evt.keyCode;
if (kv == 13) {
doClick('logonBU');
return false;
}
}

//實做模擬Click的功能
function doClick(linkId) {
var o = document.getElementById(linkId);
if (document.all && typeof (document.all) == "object") //IE
o.click();
else {
var e = document.createEvent('mouseEvent');
e.initEvent('click', false, false);
o.dispatchEvent(e);
}
}

在網頁頁面的JavaScrip程式區,加入上面的程式碼後,當使用者輸入資料後,習慣性按下Enter鍵時,就會執行和按下loginBU Click相同的事件功能。
*當輸入的資料項複雜時,就必須改寫上面的程式碼,才能正常運作。
*更複雜的資料輸入頁面的處理原則,留待下篇文章說明與討論。

後記:
如有任何建議或改善意見,歡迎隨時來函指正或討論。Thanks.

2009年2月20日 星期五

在Windows平台使用JSP Solution時, 如何引用Com元件,增加系統功能?

問題說明:
最近開發一套Windows平台Web Application 的單一簽入系統,須要讓JSP引用已開發好的單一簽入開發端元件;免得重寫開發端元件,也有利於系統的維護。因此,尋找相關的解決方案。
在ASP Solution中有Server.CreateObject("元件名稱")可以引用COM元件。
在PHP Solution中有new COM("元件名稱")可以引用Com元件。
JSP Solution引用Com元件的解決方案如下:
1.須取得JACOB套件,安裝於JAVA 2 SDK中。
2.使用JACOB套件的new ActiveXComponent("元件名稱")或new Dispatch("元件名稱")功能。
由於此元件的搜尋與安裝有些複雜,因此記錄於此,隨時提供備忘索引;也分享給有此需求的網友。

JACOB簡介:
JACOB is a JAVA-COM Bridge that allows you to call COM Automation components from Java.
官方網站:http://danadler.com/jacob/

JACOB下載:
下載JACOB1.7版
下載JACOB1.14.3版

JACOB安裝:
1.在j2sdk所在資料夾,建立一次目錄:com;再將下載檔案解縮後的jacob.dll複製至此目錄。
2.將下載檔案解縮後的jacob.jar複製到j2sdk所在資料夾的lib次目錄。
3.CLASSPATH環境變數加入,jacob.jar所在路徑。
4.PATH環境變數加入,jacob.dll所在路徑。
注意1:設定上面環境變數時,需要保留原來的設定值;也就是說是附加不是取代。如果取代了上面的環境變數,可能會引起系統運作不正常。
注意2:JACOB如果安裝1.14.3版,web server使用Resin時,須升級至:3.2以上版本。
下面環境變數設定是以JDK1.6.0-12為例:
CLASSPATH=.;C:\Program Files\Java\jdk1.6.0_12\lib\tools.jar;C:\Program Files\Java\jdk1.6.0_12\lib\dt.jar
Path=C:\Program Files\Java\jdk1.6.0_12;C:\Program Files\Java\jdk1.6.0_12\bin;C:\Program Files\Java\jdk1.6.0_12\com
JAVA_HOME=C:\Program Files\Java\jdk1.6.0_12

接著就可以開始撰寫JSP程式囉:
引用ActiveXCom元件時,使用:new ActiveXComponent("元件名稱.Class名稱")
引用一般Com元件時,使用:new Dispatch("元件名稱.Class名稱")
JOCA官方網站,範例程式碼如下:
ActiveXComponent xl = new ActiveXComponent("Excel.Application");
Object xlo = xl.getObject();
try {
System.out.println("version="+xl.getProperty("Version"));
System.out.println("version="+Dispatch.get(xlo, "Version"));
xl.setProperty("Visible", new Variant(true));
Object workbooks = xl.getProperty("Workbooks").toDispatch();
Object workbook = Dispatch.get(workbooks,"Add").toDispatch();
Object sheet = Dispatch.get(workbook,"ActiveSheet").toDispatch();
Object a1 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {"A1"},
new int[1]).toDispatch();
Object a2 = Dispatch.invoke(sheet, "Range", Dispatch.Get,
new Object[] {"A2"},
new int[1]).toDispatch();
Dispatch.put(a1, "Value", "123.456");
Dispatch.put(a2, "Formula", "=A1*2");
System.out.println("a1 from excel:"+Dispatch.get(a1, "Value"));
System.out.println("a2 from excel:"+Dispatch.get(a2, "Value"));
Variant f = new Variant(false);
Dispatch.call(workbook, "Close", f);
} catch (Exception e) {
e.printStackTrace();
} finally {
xl.invoke("Quit", new Variant[] {});
}

個人自行開發元件引用程式碼如下:
Dispatch ctsso= new Dispatch("SSOUtilNoneAspx.CTSSOUtil");
Variant cookieDomain=Dispatch.call(ctsso,"GetCookieDomain",new Variant(true));
Variant cookieName=Dispatch.call(ctsso,"GetCookieName",new Variant(true));
Variant result= Dispatch.call(ctsso,"IsAuthenticated", new Variant(kValue),new Variant(""));

2009年2月7日 星期六

ADSI技術文章-使用LDAP Provider取得User的Primary Group

DirectoryEntry domain=new DirectoryEntry(ladpPath, accountName, pwd);
search.SearchScope = SearchScope.Subtree;
search.Filter = "(objectclass=User)";
SearchResult result = search.FindOne();
object primaryGroupID=result.Properties["primaryGroupID"][0];
DirectoryEntry gEntry = new DirectoryEntry(ldapRootPath,account,password);
DirectorySearcher search = new DirectorySearcher(gEntry);
search.SearchScope = SearchScope.Subtree;
search.Filter = "(objectclass=group)";
string rv = string.Empty;
try
{
SearchResultCollection result = search.FindAll();
string sid;
foreach (SearchResult sr in (IEnumerable)result)
{
sid = ObjectIdToString((byte[])sr.Properties["objectsid"][0]);
if (sid.EndsWith(primaryGroupID.ToString()) == true)
{
rv = sr.Properties["cn"][0].ToString();
break;
}
}
}
catch{
}


public string ObjectIdToString(byte[] oSid)
{
SecurityIdentifier sid = new SecurityIdentifier(oSid, 0);
return sid.ToString();
}

//重點提示:group objectSid 的尾碼==PrimaryGroupID

ADSI技術文章-使用LDAPProvider取得User的Groups

//方法一(ldap path 需包含使用者名稱)
DirectoryEntry domain=new DirectoryEntry(ladpPath, uName, pwd);
search.SearchScope = SearchScope.Subtree;
search.Filter = "(objectclass=User)";
SearchResult result = search.FindOne();
IADsUser iu = (IADsUser)result.GetDirectoryEntry().NativeObject;
List rv = new List();
foreach (IADsGroup item in (IEnumerable)iu.Groups())
rv.Add(item.Name.Split('=')[1]);

//方法二(ldap path 不包含使用者名稱)
DirectoryEntry domain=new DirectoryEntry(ladpPath, uName, pwd);
search.SearchScope = SearchScope.Subtree;
search.Filter = string.Format("(&(objectclass=User)(CN={0})",uName);
SearchResult result = search.FindOne();
IADsUser iu = (IADsUser)result.GetDirectoryEntry().NativeObject;
List rv = new List();
foreach (IADsGroup item in (IEnumerable)iu.Groups())
rv.Add(item.Name.Split('=')[1]);

-------------------------------------
使用IADsUser的Groups取得User的Groups
注意:此方法取得的Groups並不包含PrimaryGroup