none
如何讓form上面的datagridview能即時顯示資料庫的資料? RRS feed

  • 問題

  • 我是使用SqlDataReader來讀取資料表的資料
    將讀回來的資料放到datagridview
    然後每五秒會再讀一次資料表,將拿到的資料放入datagridview
    但這樣做datagridview的顯示就會一直閃爍
    請問有比較好的做法可以讓即時顯示資料表的資料嗎?謝謝。


    感謝Bill Chung的建議,補充我的程式碼…如下,謝謝
            //定時去scan
     private void TimerSet() 
            {          
                timer1.Interval = 5000;
                auto = true;
                timer1.Tick += new EventHandler(AutoUpdatTimerEvent);
                timer1.Start();
            }

     private void AutoUpdatTimerEvent(object sender, EventArgs e)
            {
          UpdateForm();
     }

           private void UpdateForm()
            {            
                try
                {
                    string sSql = string.Format("select * from [EQUIPMENT] ");
                    SqlDataReader reader = CDBManager.Singleton.GetRead(sSql);

                    //將資料放入datagridview
                    DataTable dt = new DataTable();
                    dt.Load(reader, LoadOption.OverwriteChanges);
                    datagridview.DataSource = dt;
                }
                catch (Exception ex)
                {
                    LogErr("UpdateForm:" + ex.Message);
                }
            }

    • 已編輯 ccfgui 2010年1月4日 上午 10:09
    2010年1月4日 上午 09:43

解答

  • 這邊有一個範例, 我習慣在外部Invoke, 在多緒中只要將值傳出就好, 不要去碰觸任何UI相關.
    這個範例也使用了BindingSource類別當中介, 一併解決你新的發問
     public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            public delegate void UI(String str1, String str2);
            public void UIDispaly(String str1, String str2)
            {
                if (this.dataGridView1.InvokeRequired == true)
                {
                    this.dataGridView1.BeginInvoke (new UI(UIDispaly ), new object[] {str1,str2});
                }
                else
                {
                    DataRow myRow=DT.NewRow();
                    myRow[0]=str1;
                    myRow[1]=str2;
                    DT.Rows.Add (myRow);
                }
            }
            private  BindingSource BS = new BindingSource();
            private DataTable DT =new DataTable ();
           
            private void Form1_Load(object sender, EventArgs e)
            {
                BuildDT();
            }
            private void BuildDT()
            {
                DT.Columns.Add("Col0");
                DT.Columns.Add("Col1");
                BS.DataSource = DT;
                dataGridView1.DataSource = BS;

            }

            private void button1_Click(object sender, EventArgs e)
            {
                Thread dataproc = new Thread(new ThreadStart(UpadteProc));
                dataproc.Start();

            }
            private void UpadteProc()
            {
                int i;
                for (i = 0; i <= 1000; i++)
                {
                    UIDispaly(i.ToString(), "ABC" + i.ToString());
                    Thread.Sleep(100);
                }
            }
        }

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題的熱情
    • 已標示為解答 ccfgui 2010年1月6日 上午 09:06
    2010年1月5日 上午 05:37
    版主

所有回覆

  • 這樣形容, 不知道你是如何更新的, 可以貼重點的程式碼上來, 也許比較能激發大家思考

    請讀一下這篇文

    張貼文章應注意事項及應提供資訊

    會有助於你更快獲得大家的回應


    學而不思則罔, 思而不學則殆.
    如果你一直都看不懂、不想學習看懂、抗拒看懂MSDN Library的話,那你最好放棄想要寫好程式這件事
    如果你自私地不肯回饋與分享,那別人為何要花時間回答你的問題?
    2010年1月4日 上午 09:54
    版主
  • Hi,
    您的資料很大嗎?
    若是的話,可能要考慮一下在間隔時間內是否讀取的完
    若讀取的完,可考慮用Virtual Mode來改善效率


    謙卑學習,持之以恆,才能不斷的Level Up http://www.dotblogs.com.tw/larrynung/
    2010年1月4日 上午 10:31
  • 幾個建議
    1. 不要用Timer, 除非你可以確定不會發生五秒讀不完的現象, 改用多執行緒做會好一點
    2. 不要每次都讀全部資料, 你可以利用資料表的自動編號欄位讓程式知道你已經讀到哪一筆, 下次就從以下編號開始讀 , 然後用DataTable.Rows.Add 把新增的加進來就好


    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題的熱情
    2010年1月4日 上午 10:45
    版主
  • 感謝各位的建議,有幾個問題想問一下
    1.Virtual Mode這方面沒接觸過,會在study一下
    2.當我使用執行緒時,有發生下列問題,請問應該要怎麼處理?謝謝

            private bool flag;
            public delegate void MyInvoke(DataGridView dg);
            private void threadProc()
            {
                while (flag)
                {
                    AutoUpdatEvent();
                    Thread.Sleep(5000);
                }
            }
            private void AutoUpdatEvent()
            {
                    string sSql = string.Format("Select * from [EQUIPMENT]");
                    SqlDataReader reader = CDBManager.Singleton.GetRead(sSql);

                    DataTable ds = new DataTable();
                    ds.Load(reader, LoadOption.OverwriteChanges);

                    MyInvoke mi = new MyInvoke(BindDataGridView);
                    this.BeginInvoke(mi, new object[] { ds });       //程式跑到此行即出現下列問題
                    //Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
     }
            private void BindDataGridView(DataGridView ds)
            {
                dgProRecipe.DataSource = ds;
                dgProRecipe.Columns["part_id"].Frozen = true;
            }

    2010年1月5日 上午 03:52
  • 如題,
    我是使用SqlDataReader來讀取資料表的資料,將讀回來的資料放到datagridview
    sql中的資料表有十筆紀錄,每十秒就會更新某幾筆資料
    datagridview在更新前游標是停在第五行、第五列
    請問我要如何讓datagridview更新後,游標也停在相同位置,謝謝
    • 已合併 Lolota Lee 2010年1月5日 上午 05:41
    2010年1月5日 上午 03:56
  • hi
    將BeginInvoke改成Invoke試看看
    private void AutoUpdatEvent()
            {
                    string sSql = string.Format("Select * from [EQUIPMENT]");
                    SqlDataReader reader = CDBManager.Singleton.GetRead(sSql);

                    DataTable ds = new DataTable();
                    ds.Load(reader, LoadOption.OverwriteChanges);

                    MyInvoke mi = new MyInvoke(BindDataGridView);
                    Invoke(mi, new object[] { ds });       //程式跑到此行即出現下列問題
                    //Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
     }


    http://www.dotblogs.com.tw/ricochen/Default.aspx
    2010年1月5日 上午 05:26
  • 這邊有一個範例, 我習慣在外部Invoke, 在多緒中只要將值傳出就好, 不要去碰觸任何UI相關.
    這個範例也使用了BindingSource類別當中介, 一併解決你新的發問
     public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
            public delegate void UI(String str1, String str2);
            public void UIDispaly(String str1, String str2)
            {
                if (this.dataGridView1.InvokeRequired == true)
                {
                    this.dataGridView1.BeginInvoke (new UI(UIDispaly ), new object[] {str1,str2});
                }
                else
                {
                    DataRow myRow=DT.NewRow();
                    myRow[0]=str1;
                    myRow[1]=str2;
                    DT.Rows.Add (myRow);
                }
            }
            private  BindingSource BS = new BindingSource();
            private DataTable DT =new DataTable ();
           
            private void Form1_Load(object sender, EventArgs e)
            {
                BuildDT();
            }
            private void BuildDT()
            {
                DT.Columns.Add("Col0");
                DT.Columns.Add("Col1");
                BS.DataSource = DT;
                dataGridView1.DataSource = BS;

            }

            private void button1_Click(object sender, EventArgs e)
            {
                Thread dataproc = new Thread(new ThreadStart(UpadteProc));
                dataproc.Start();

            }
            private void UpadteProc()
            {
                int i;
                for (i = 0; i <= 1000; i++)
                {
                    UIDispaly(i.ToString(), "ABC" + i.ToString());
                    Thread.Sleep(100);
                }
            }
        }

    MSDN 文件庫很重要
    問題本身越具體, 越容易得到大家的回應
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題的熱情
    • 已標示為解答 ccfgui 2010年1月6日 上午 09:06
    2010年1月5日 上午 05:37
    版主