none
很怪,textBox_Leave() 中改變欄位內容,Text 會被清空 RRS feed

  • 一般討論

  • 各位好,很怪。
    用 VS2015 Community,情況很簡單。我做了一個系統登入帳號的管理畫面 Winform,用 Typed DataSet, BindingSource, 目前為止,查詢、新增、修改、刪除、儲存、放棄等功能,都工作正常,執行後到資料庫查,也反應出最新資料。但程式還差一段,就是新增後,在員工編號的 textBox 打員工編號,按 Tab 離開後,要能從資料庫找出員工名稱,填入員工名稱的欄位。

    新增時用 SqlDataAdapter 下這道指令 select * from 系統登入帳號 where 員工編號=''

    然後在 dataTable 加一列

            private void tbUserId_Leave(object sender, EventArgs e)
            {
                if (WorkState == "A" && tbUserId.Text != "")  // 新增時 WorkState == "A"  才會執行
                {
                    feDataSet1.系統登入帳號[0].員工名稱 = DBHelper.GetData(tbUserId.Text, 略...);  // 執行正確
                   // 執行上面那一行後,feDataSet1.系統登入帳號[0].員工編號,仍然是 null,tbUserId.Text 被清空
                   // MessageBox.Show(feDataSet1.系統登入帳號[0].員工編號); 用這行檢查,會跳出  DbNull 錯誤訊息
                }
            }

            private void tbUserId_Leave(object sender, EventArgs e)
            {
                if (WorkState == "A" && tbUserId.Text != "")  // 新增時 WorkState == "A"  才會執行
                {
                    feDataSet1.系統登入帳號[0].異動人員="陳老大";  // 改用這行測試另一個欄位,情形跟上面一樣      
                }
            }

    private void tbUserId_Leave(object sender, EventArgs e)
            {
               // 清空程式碼,就不會有以上問題,即 tbUserId 輸入員工編號,按 tab 離開,tbUserId 內容不會被清空
              // 另外在放棄按鈕用 MessageBox.Show(feDataSet1.系統登入帳號[0].員工編號),會秀出員工編號 (即不是 null)
            }


    簡言之,DataTable 新增一列後,只要在 tbUserId_Leave() 用程式碼改變 DataTable 任何一個欄位的內容,DataTable 就不接受 tbUserId 輸入的文字(丟掉),有誰能解惑呢?我的 dll 群大量使用 "離開編號帶出名稱或說明" 的程式碼,這個搞不定就一直卡在這裡,謝謝。

    2016年11月4日 上午 03:34

所有回覆

  • 你沒貼出你是怎麼處理 DataTable 新增一列這件事。

    feDataSet1.系統登入帳號[0].員工名稱 = DBHelper.GetData(tbUserId.Text, 略...);  // 執行正確

    但沒有看到你在哪給員工編號,這樣會有資料才有鬼吧?


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月4日 上午 05:23
    版主
  • Hello, 畫面每次只會有一筆資,新增很簡單,按新增按鈕呼叫 ReadData() 讀取資料

      private void btnA_Click(object sender, EventArgs e)  // 新增的按鈕
            {
                ReadData("");  // 傳入空白讀取零筆     
                FEDataSet.系統登入帳號Row dataRow = feDataSet1.系統登入帳號.New系統登入帳號Row();
                feDataSet1.系統登入帳號.Add系統登入帳號Row(dataRow);  // DataTable 加一筆
            }

    private void ReadData(string UserId)  // UserId 有內容表示查詢,沒有內容表示新增
            {    
                string sql;      
                sql = string.Format("select * from 系統登入帳號 where 員工編號='{0}'", UserId);
                //  if (UserId == "")     // 參考討論區, 這樣新增讀零筆, 但發現執行時會出錯
                //     sql = "select * from 系統登入帳號 where 0=1'"; 
                feDataSet1.Clear();  // Fill() 會附加資料到 dataset, 故清空
            
                if (adapter == null)  // 表單變數,第一次讀取資料庫時建立,儲存時要用到
                       adapter = new SqlDataAdapter(sql, cnn);                 
                else adapter.SelectCommand.CommandText = sql;

                var cb = new SqlCommandBuilder(adapter);        
                adapter.InsertCommand = cb.GetInsertCommand(true);
                adapter.UpdateCommand = cb.GetUpdateCommand(true);
                adapter.DeleteCommand = cb.GetDeleteCommand(true);
                adapter.Fill(feDataSet1, "系統登入帳號");
            }

    2016年11月4日 上午 05:54
  • 不貼還好,一貼馬上就被抓到 SQL Injection。

    另外,我只看到重新更新 DataSet,但沒看到你的新增到資料庫的程序,這樣員工編號要怎麼來?


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月4日 上午 05:59
    版主
  • Hello,
    1.不貼還好,一貼馬上就被抓到 SQL Injection。

    上面有寫是 WinForm,不是 WebForm,應無 SQL Injection 問題。

    2.我只看到重新更新 DataSet,但沒看到你的新增到資料庫的程序,這樣員工編號要怎麼來?

    你是說先 insert 系統登入帳號 (員工編號) Values('') 再讀回來修改嗎?這個方法我昨天上網有看過有人這樣用,但是,兩個人同時新增就死了 ! 另外有一個叫 [員工] 的資料表,鍵值也是員工編號,新增後,在 tbUserId 輸入員工編號,離開時呼叫另一個函式把 [員工] 的員工名稱抓進來,填入 tbUserName,其實這個沒必要,儲存時再把員工名稱抓進來也可以,但我們的程式都是一律要求 "馬上反應",不能等儲存後才知道輸入錯誤的員工編號。

    我是先讀零筆,DataTable 加一筆,按儲存時:

    // 必要的檢查...
    bindingSource1.EndEdit();           
    adapter.Update(feDataSet1.系統登入帳號);
    feDataSet1.系統登入帳號.AcceptChanges();


    2016年11月4日 上午 07:01
  • 1. 請問是哪位告訴你說不是 Web Form 就可以當沒 SQL Injection...你這麼相信使用者喔?

    2. 兩個人同時新增會死掉,你資料庫是 Access 嗎? 若是,這個問題就無解了,除非另外寫一層,由那一層程式去讀寫 Access 資料庫。若是 SQL Server,可以直接在 INSERT 後用 SELECT @@IDENTITY 取得編號 (假設是用流水號,若是自訂格式編號,你要另外想辦法處理),一樣可以在很短時間內反應。

    "馬上反應" 這個詞太過感覺化,要明確定義出量化數值 (例如1秒內或3秒內) 才有討論空間。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月4日 上午 07:40
    版主
  • (1) SQL Injection 跟是不是web無關,只要AP會跟db溝通就是要注意SQL Injection問題

    (2) 新增時你要檢查key值存不存在,可以在輸入完工號時就用ajax去檢查,這樣是可以很即時的,也就是你所謂的馬上反應


    微軟免費線上課程

    HTML5 & JavaScript程式開發實戰(MyBook)

    開發ASP.NET您要瞭解的基楚

    http://www.dotblogs.com.tw/ian (MyBlog)

    2016年11月4日 上午 07:55
  • 朱大,
    1.若是 SQL Server,可以直接在 INSERT 後用 SELECT @@IDENTITY 取得編號 (假設是用流水號,若是自訂格式編號,你要另外想辦法處理),一樣可以在很短時間內反應。
    一樣會中標,我們的程式三不五時都有主鍵值重複的問題,我都要到資料庫去改。怎會這樣?因為有些人的網路連線比較慢(分公司)有些人比較快(總公司),兩人同時取號,以您的例子來講就好,分公司的人 insert,因為網路較慢,總公司內部的人也 insert,分公司的人下 SELECT @@IDENTITY,拿到總公司同事的號碼了。

    2."馬上反應" 這個詞太過感覺化,要明確定義出量化數值 (例如1秒內或3秒內) 才有討論空間。
    就是一般人能夠接受的時間,打入客戶編號,帶出客戶名稱,如果花了一分鐘,我相信沒有人會接受,花半秒每個人都沒意見,花五秒或以上?可能就...


    2016年11月4日 上午 08:21
  • Hello, 看得出為什麼 textbox 文字消失的原因嗎?DataTable 讀取零筆,然後 DataTable 供使用者輸入,此時 DataTable 的員工編號是 null,在 textBox 輸入員工編號,按 Tab 離開,textBox.Text 會寫入 DataTable 的員工編號,這是正常的。我在儲存時才補上員工名稱,這樣沒問題。但如果我在 textBox_Leave() 中把字串寫入 DataTable 任何一個欄位,DataTable 就不會接受 textBox.Text 的內容,而且還把 DataTable 的員工編號(此時是 null) 倒灌回來 textBox.Text,造成 textBox.Text 原本的字消失。
    2016年11月4日 上午 08:28
  • 這種情況我會偏好使用 GUID 來處理,然後再另外產生一個可讀的編號出來,取號的工作也可以另外由程式來做,只有這支程式能決定資料的編號。

    不過你說的這個 case,其實可以 INSERT 完馬上跑 SELECT @@IDENTITY (SQL Server 還有另外兩種,你可以選擇適合你的作法),這樣就不會有因為網路慢而取錯號的問題了,這個方法網路上很多了,搜尋一下就有...

    1分鐘和1秒鐘感覺上就差很多,所以我才要你定出一個可接受的時間,例如 5 秒,那要做到 5 秒內得到結果,你的程式 (甚至是架構) 要怎麼調,才有討論的空間啊。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月4日 上午 08:35
    版主
  • 我覺得你用錯事件了。

    Leave 是給表單用的,文字方塊要用 LostFocus 比較好。

    ref: http://stackoverflow.com/questions/15941562/issue-with-lostfocus-event-of-a-textbox


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月4日 上午 08:37
    版主
  • Hello, 剛看過以下,LostFocus() 是寫元件用的

    https://social.msdn.microsoft.com/Forums/en-US/dd023378-d700-4c5f-a5b5-072fd4de7903/lostfocus-vs-leave-events?forum=Vsexpressvb

    2016年11月7日 上午 12:51
  • Hello,我比較不傾向這種用 insert 再抓回來方新增方式,因為需要 insert,select,update 三動才能做一件簡單的新增資動作,且使用者如果按 [放棄] 按鈕,還得用 delete 把它刪掉。再者,Master table 可以這樣做可以,如果是 detail table,少則幾筆,多則幾百筆,我們試過一張單子中有八千多筆的 detail 資料,不可能每新增一筆 detail 就 insert 到資料庫。
    2016年11月7日 上午 01:00
  • 如果你要死抓著一定要由資料庫產生 identity 的做法,那我只能跟你說無解,我前面也有說我偏號用 GUID,細節的編號另外給。

    若對編號有莫名的堅持,那只好自己寫一個編號產生的程式去處理編號取號,還比遷就於由資料庫產生 identity 要來得快。


    強力監督SQL Injection問題!!

      • 小朱的技術隨手寫:http://www.dotblogs.com.tw/regionbbs/
      • 雲端學堂Facebook: http://www.facebook.com/studyazure

    2016年11月7日 上午 01:53
    版主
  • 剛又試過,把它儲存後再按修改,在員工編號打其他的編號,按 Tab 離開,結果是相反。

    新的員工編號沒有消失或清空,但員工名稱卻帶不出來,還是原來的員工名稱。

    猜是 BindingSource 的問題,原來的 BindingSource 不要,在 TextBox 的 DataBinding 重選 DataTable 的欄位,原來會產生新的BindingSource, 不是 BindingSource 的問題。

    查遍網頁都沒有類似個案,心力交瘁了!

    論譠怪怪的,按鈕上文字變成 [Enviar] 和 [Cancelar],法文、西班牙文之類的

    2016年11月7日 上午 02:23
  • 大概知道原因了:
    1.當 DataTable 新增一筆後,此時所有欄位都沒有值,如果用程式碼去填入某個欄位,DataTable 會把所有欄位內容填入跟它 DataBind 的所有控制項。
    2. 輸入焦點離開 TextBox 時,是先引發 TextBox.Leave 事件,再把 TextBox.Text 填入 DataTable 對應欄位。

    根據以上,當我新增一筆資料,在 tbUserId 輸入員工編號再按 Tab 後,TextBox.Leave 事件用 tbUserId.Text 向資料庫要員工名稱,程式把員工名稱填入 DataTable.員工名稱時,觸發了一次 DataTable 對控制項的刷新,因此時 DataTable.員工編號仍是 null 值,tbUserId.Text 就被填入 null,TextBox.Leave過後 tbUserId 要把員工編號填入 DataTable.員工名稱,因此時是 null,員工編號消失了。

    解決方法就是在 Leave 事件第一行先填回去

     private void tbUserId_Leave(object sender, EventArgs e)
            {          
                    feDataSet1.系統登入帳號[0].員工編號 = tbUserId.Text;   // 搶先填回去
                  //  .. 略   
            }

    2016年11月7日 上午 03:37
  • 這樣比較好

    private void tbUserId_Leave(object sender, EventArgs e)
            {          
                    BindingSource.EndEdit();  // 效果一樣
                  //  .. 略   
            }

    2016年11月7日 上午 03:56