DataSet / BindingSource / DataGridView / BindingNavigator 的關系與綁定、修改數據庫


一、說明

1.數據源DataSet是保存數據,以及發布數據更新通知的核心。
2.BindingSource,是控件(DataGridView / BindingNavigator)與數據源交互的橋梁。BindingSource的DataSource指向數據源DataSet之后,數據源或控件的數據更改,則會被BindingSource傳遞到另一頭。
3.DataGridView / BindingNavigator是數據控件,它們應該從BindingSource獲取數據。當數據控件的數據,被用戶更改后,則會通知BindingSource,接着BindingSource再通知數據源DataSet。

因此,這些組件綁定與更新的順序為:

1.創建DataSet
2.把BindingSource的BindingSource綁定到DataSet。
3.把DataGridView的DataSource,以及BindingNavigator的BindingSource,都綁定到BindingSource。
關鍵:如果DataSet的數據發生變化,或者DataGridView / DataSource的數據發生變化,則雙向的更改是自動進行與傳遞的。
但如果DataSet被替換,則需要把BindingSource的BindingSource重新綁定到DataSet。DataGridView 與 BindingNavigator則不需要更改,因為BindingSource會自動通知他們。
同理,如果DataGridView的DataSource,以及BindingNavigator的BindingSource被替換,也就是他們的BindingSource被替換,則DataSet也需要重新綁定到新的BindingSource中。注意,DataGridView的DataSource,以及BindingNavigator的BindingSource,應該被替換為同一個BindingSource,這樣他們才能具有可交互性。

 

二、例子

 

 

 

 代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication4
{
    public partial class Form1 : Form
    {
        DataSet ds = new DataSet();
        string conn = "Data Source = (local)\\SQLEXPRESS; Initial Catalog = northwind; Persist Security Info = True;User ID=sa;Password=6617saSA";
        string sql = "SELECT CustomerID  編號,CompanyName  ,ContactName ,ContactTitle  ,Address ,City  FROM Customers ;";
        SqlDataAdapter sda ;
        BindingSource bindingsource1 ;
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.AllowUserToAddRows = false; //去掉DataGridView的最后一個空行
            bindingsource1 = new BindingSource();
            sda = new SqlDataAdapter(sql, conn);
            sda.Fill(ds, "Customers");    
            bindingsource1.DataSource = ds;
            bindingsource1.DataMember = ds.Tables[0].TableName;
            bindingNavigator1.BindingSource = bindingsource1;
            dataGridView1.DataSource = bindingsource1;

            //textBox_ID.DataBindings.Add("text", bs, "編號",false, DataSourceUpdateMode.OnPropertyChanged);
            //textBox_name.DataBindings.Add("text", bs, "CompanyName", false, DataSourceUpdateMode.OnPropertyChanged);
            textBox_ID.DataBindings.Add("text", bindingsource1, "編號");
            textBox_name.DataBindings.Add("text", bindingsource1, "CompanyName");

            textBox_ContactName.DataBindings.Add("text", bindingsource1, "ContactName");
            textBox_ContactTitle.DataBindings.Add("text", bindingsource1, "ContactTitle");
            textBox_Address.DataBindings.Add("text", bindingsource1, "Address");
            textBox_City.DataBindings.Add("text", bindingsource1, "City");
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            //該語句使修改cell內容后直接保存有效,否則需要移動到其它CELL再保存才有效
            dataGridView1.CurrentCell = null; 
            //將控制修改內容更新到DataSet基礎數據,如果沒有EndEdit() , ds.GetChanges() == null永遠成立
            ((BindingSource)dataGridView1.DataSource).EndEdit();
            if (ds.GetChanges() != null)
            {
                //沒有下一條會出現錯誤:當傳遞具有新行的 DataRow 集合時,Update 要求有效的 InsertCommand
                SqlCommandBuilder sb1 = new SqlCommandBuilder(sda);
                sda.Update(ds.Tables["Customers"]);//更新數據庫
                ds.AcceptChanges();
            }
        }

        private void label2_Click(object sender, EventArgs e)
        {

        }

        private void textBox_ContactName_TextChanged(object sender, EventArgs e)
        {

        }
    }
}

 

三、DataTable的AcceptChange方法為什么不能在Update之前?

總結:DataTable.AcceptChanges相當於將DataTable表中的所有DataRow的RowState狀態 重置為Unchanged

DataTable.RejectChanges方法:回滾自該表加載以來或者上次調用AcceptChanges以來對該表進行的所有更改;並且DataTable表中的所有DataRow的RowState狀態 重置為Unchanged

例子:

DataTable dataTable = ds.Tables[0];

dataTable.Rows[0][0] = 96.6669;//此時的RowState為Modied

dataTable.AcceptChanges();//此時的RowState為Unchanged

dataTable.Rows[0][0] = 7777;此時的RowState為Modied此時的RowState為Modied
dataTable.RejectChanges();//此時的dataTable.Rows[0][0] 為96.6669,RowState為Unchanged

 

//最后 Update需要注意的是;防止並發性的操作。有在Update執行之前所包含的數據行有被修改,則會發生並發性操作錯誤。

da.Update(dataTable);

解決並發性辦法:

if (dataTable.GetChanges() != null)
{
da.Update(dataTable.GetChanges());
}

 

AcceptChanges方法會將所有改動保存到DataSet或DataTable中,使得所有行的狀態都是Unchanged(沒有被更改狀態)

而DataAdapter.Update方法在保存數據到數據庫表時做過一個檢查,即檢查表行是否被修改過,如果沒被修改過,那么更需將不會執行任何命令,直接跳過本行,開始檢查下一行,如此,一個表如果行都是Unchanged狀態,那么它就不會被更新到數據庫中。

所以,在更改了DataSet或DataTable后,若想調用DataAdapter.Update方法直接更新數據到數據庫,那么你只需要這個Update方法,無需在此前調用一次AcceptChanges方法了。

 

Added

該行已添加到 DataRowCollection 中,AcceptChanges尚未調用。

Deleted

該行已通過 DataRow 的 Delete 方法被刪除。

Detached

該行已被創建,但不屬於任何 DataRowCollection。DataRow 在以下情況下立即處於此狀態:創建之后添加到集合中之前;或從集合中移除之后。

Modified

該行已被修改,AcceptChanges 尚未調用。

Unchanged

該行自上次調用 AcceptChanges 以來尚未更改。

 

DataTable.AcceptChanges方法:提交自上次調用AcceptChanges以來對該表進行的所有更改。

調用AcceptChanges時,任何仍處於編輯模式的DataRow對象將成功結束其編輯。DataRowState也發生更改:所有Added和Modified行成為Unchanged;Deleted行被移除。

在您嘗試使用DbDataAdapter.Update方法更新DataSet之后,通常會對DataTable調用AcceptChanges方法。

 

DataTable.RejectChanges方法:回滾自該表加載以來或上次調用AcceptChanges以來對該表進行的所有更改。

調用RejectChanges時,任何仍處於編輯模式的DataRow對象將取消其編輯。新行被移除。DataRowState設置為Modified或Deleted的行返回到其初始狀態。

會出現對DataTable進行多次更改,但是通過調用RejectChanges方法拒絕這些更改的現象

 

DataRow.BeginEdit方法:對DataRow對象開始編輯操作。

使用BeginEdit方法將DataRow置於編輯模式。在此模式中,事件被臨時掛起,以便允許用戶在不觸發驗證規則的情況下對多行進行多處更改。例如,如果需要確保總數列的值等於某行中借貸列的值,則可以將每一行都置入編輯模式,以便在用戶嘗試提交值之前掛起對行值的驗證。

BeginEdit方法在用戶更改數據綁定控件的值時被隱式調用;EndEdit方法在您調用DataTable對象的 AcceptChanges方法時被隱式調用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM