c# - 以编程方式更新 DataGridView 中的多行

标签 c# winforms datagridview

我正在创建一个 C# Windows 窗体应用程序来管理发票,我需要一些帮助来确定我是否在朝着正确的方向前进。我需要:

  • 在可编辑的网格中显示来自 SQL Server 表的一组发票(发票数量会有所不同)
  • 窗口上需要有一个文本框,用户可以在其中输入客户数据,将原始网格结果过滤到与用户输入匹配的行
  • 需要在网格顶部有一个额外的复选框,用户可以选中该复选框以更新网格中当前显示的所有行的匹配复选框列。如果输入过滤器,则检查操作应仅适用于显示的行
  • 更改不应立即提交到数据库,因为用户可能需要在将更改提交到数据库之前取消选中几行,因此还需要一个操作按钮来提交/保存更改。

我知道我可能需要使用 DataGridView 来实现这一点,但我不确定将它绑定(bind)到什么。这篇文章来自 MSDN looks promising,但我不确定如何从数据库表中填充 BindingList 类。这篇文章调用了一个 Add 方法来添加单独的行,但我希望能够一次添加所有行(或者至少有一个循环,用几行代码将它们全部添加)。

我假设 BindingList 类可以做到这一点。另外,BindingList类是否支持行过滤,类似于RowFilter类的DataView属性? StackOverflow 上还有另一篇文章引用了这个类,但它没有详细说明如何从数据库中填充 BindingList,如何对其应用过滤器,或者如何实用地更改 DataGridView 中的行。

MSDN article 似乎没有对 DGV 本身进行更改,而是对基础数据源进行了更改,然后通过 INotifyPropertyChanged 接口(interface)更新了 DGV。我知道需要播放什么,我只需要一点帮助来安排这些片段。感谢所有帮助!

我想通了,下面的代码作为其他需要帮助的人的示例。这可能是也可能不是最好的方法,但它对我有用。

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

namespace Insurance_Manager
{
    public partial class InvoiceEditor : Form
    {
        private Boolean ignoreChange = false;
        private Char type;
        private DataTable invoices;
        private SqlDataAdapter adapter;

        #region Class Constructors

        public InvoiceEditor(Char iType)
        {
            // Initialize window components
            InitializeComponent();
            type = iType;
        }

        #endregion

        #region Class Methods

        // This function calculates the grid totals
        private void CalculateTotals()
        {
            // Initialize values
            Double all = 0;
            Double doNotPay = 0;
            Double paid = 0;
            Double wrongAmount = 0;

            // Loop through each row in the displayable grid and total the rows
            foreach (DataRowView viewRow in invoices.DefaultView)
            {
                DataRow row = viewRow.Row;
                all += Double.Parse(row["Amount"].ToString());
                if (Boolean.Parse(row["DoNotPay"].ToString()) == true) { doNotPay += Double.Parse(row["Amount"].ToString()); }
                if (Boolean.Parse(row["Paid"].ToString()) == true) { paid += Double.Parse(row["Amount"].ToString()); }
                if (Boolean.Parse(row["WrongAmount"].ToString()) == true) { wrongAmount += Double.Parse(row["Amount"].ToString()); }
            }

            // Set the totals to the textbox
            tbAllTotal.Text = String.Format(all.ToString(), "{0:c}");
            tbDoNotPayTotal.Text = String.Format(doNotPay.ToString(), "{0:c}");
            tbPaidTotal.Text = String.Format(paid.ToString(), "{0:c}");
            tbWrongAmtTotal.Text = String.Format(wrongAmount.ToString(), "{0:c}");
        }

        // This functions loads the invoices for the grid
        private void LoadInvoices()
        {
            // Fill the data table
            SqlConnection conn = new SqlConnection("Data Source=REPORTSERVER;Initial Catalog=Insurance;Integrated Security=True");
            conn.Open();
            String query = "";
            query += "Select ";
            query += "  IsNull(C.CustomerName,'') CustomerName, ";
            query += "  IsNull(C.[Contract],'') [Contract], ";
            query += "  IsNull(Convert(VarChar(20),I.Receipt),'') Receipt, ";
            query += "  IsNull(I.PolicyNumber,'') PolicyNumber, ";
            query += "  IsNull(I.[Type],'') [Type], ";
            query += "  I.DateBilled, ";
            query += "  I.Amount, ";
            query += "  I.DatePaid, ";
            query += "  I.Paid, ";
            query += "  I.DoNotPay, ";
            query += "  I.WrongAmount, ";
            query += "  I.ID, ";
            query += "  IsNull(I.Notes,'') Notes ";
            query += "From ";
            query += "  Invoice I ";
            query += "  Join Customer C On I.CustomerID = C.ID ";
            switch (type)
            {
                case 'A':
                    query += "Where I.ID Is Not Null And I.CustomerID Is Not Null ";
                    break;
                case 'C':
                    query += "Where I.CustomerID Is Null ";
                    break;
                case 'N':
                    query += "Where I.DoNotPay = 1 And I.CustomerID Is Not Null ";
                    break;
                case 'P':
                    query += "Where I.Paid = 1 And I.CustomerID Is Not Null ";
                    break;
                case 'U':
                    query += "Where I.DoNotPay = 0 And I.Paid = 0 And I.CustomerID Is Not Null ";
                    break;
                case 'W':
                    query += "Where I.WrongAmount = 1 And I.CustomerID Is Not Null ";
                    break;
            }
            query += "Order By ";
            query += "  I.DateBilled ";
            adapter = new SqlDataAdapter(query, conn);
            invoices = new DataTable();
            adapter.Fill(invoices);

            // Link the data table to the grid
            dgvInvoices.DataSource = invoices;
            dgvInvoices.Columns[0].DataPropertyName = "CustomerName";
            dgvInvoices.Columns[0].ReadOnly = true;
            dgvInvoices.Columns[1].DataPropertyName = "Contract";
            dgvInvoices.Columns[1].ReadOnly = true;
            dgvInvoices.Columns[2].DataPropertyName = "Receipt";
            dgvInvoices.Columns[2].ReadOnly = true;
            dgvInvoices.Columns[3].DataPropertyName = "PolicyNumber";
            dgvInvoices.Columns[3].ReadOnly = true;
            dgvInvoices.Columns[4].DataPropertyName = "PolicyNumber";
            dgvInvoices.Columns[4].ReadOnly = true;
            dgvInvoices.Columns[5].DataPropertyName = "DateBilled";
            dgvInvoices.Columns[5].ReadOnly = true;
            dgvInvoices.Columns[6].DataPropertyName = "Amount";
            dgvInvoices.Columns[6].DefaultCellStyle.Format = "c";
            dgvInvoices.Columns[7].DataPropertyName = "DatePaid";
            dgvInvoices.Columns[8].DataPropertyName = "Paid";
            dgvInvoices.Columns[9].DataPropertyName = "DoNotPay";
            dgvInvoices.Columns[10].DataPropertyName = "WrongAmount";
            dgvInvoices.Columns[11].DataPropertyName = "ID";
            dgvInvoices.Columns[11].Visible = false;
            dgvInvoices.Columns[12].DataPropertyName = "Notes";
            dgvInvoices.Columns[12].Visible = false;

            // Close the database connection
            conn.Close();

            // Calculate totals
            CalculateTotals();
        }

        // This function resets all of the fields
        private void ResetFields()
        {
            // Turn on the ignore change flag
            ignoreChange = true;

            // Reset actions
            cbDoNotPay.Checked = false;
            cbPaid.Checked = false;
            cbWrongAmt.Checked = false;

            // Reset filter fields
            dpMinDateBilled.Text = "1/1/1900";
            dpMaxDateBilled.Text = "12/31/2099";
            dpMinDatePaid.Text = "1/1/1900";
            dpMaxDatePaid.Text = "12/31/2099";
            tbContract.Text = "";
            tbName.Text = "";
            tbPolicy.Text = "";
            tbReceipt.Text = "";

            // Turn off the ignore change flag
            ignoreChange = false;
        }

        // This function saves the row to the database
        private void Save(DataRow row)
        {
            // Format values as needed
            Double amount = Double.Parse(row["Amount"].ToString());
            Int32 receipt;
            try
            {
                receipt = Int32.Parse(row["Receipt"].ToString());
            }
            catch
            {
                receipt = 0;
            }

            // Acquire a connection to the database
            SqlConnection conn = new SqlConnection("Data Source=REPORTSERVER;Initial Catalog=Insurance;Integrated Security=True");
            conn.Open();

            // Save the customer to the database
            SqlCommand cmd = new SqlCommand("usp_SaveInvoice", conn);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@InvoiceID", SqlDbType.Int).Value = row["ID"];
            if (receipt != 0)
            {
                cmd.Parameters.Add("@Receipt", SqlDbType.Int).Value = row["Receipt"];
            }
            else
            {
                cmd.Parameters.Add("@Receipt", SqlDbType.Int).Value = DBNull.Value;
            }
            cmd.Parameters.Add("@Type", SqlDbType.VarChar, 10).Value = row["Type"];
            cmd.Parameters.Add("@Policy", SqlDbType.VarChar, 15).Value = row["PolicyNumber"];
            cmd.Parameters.Add("@DateBilled", SqlDbType.Date).Value = DateTime.Parse(row["DateBilled"].ToString());
            cmd.Parameters.Add("@Amount", SqlDbType.Money).Value = amount;
            if (row["DatePaid"].ToString().Equals(""))
            {
                cmd.Parameters.Add("@DatePaid", SqlDbType.Date).Value = DBNull.Value;
            }
            else
            {
                cmd.Parameters.Add("@DatePaid", SqlDbType.Date).Value = DateTime.Parse(row["DatePaid"].ToString());
            }
            cmd.Parameters.Add("@Paid", SqlDbType.Bit).Value = row["Paid"];
            cmd.Parameters.Add("@DoNotPay", SqlDbType.Bit).Value = row["DoNotPay"];
            cmd.Parameters.Add("@WrongAmount", SqlDbType.Bit).Value = row["WrongAmount"];
            cmd.Parameters.Add("@Notes", SqlDbType.VarChar, 200000000).Value = row["Notes"];
            cmd.Parameters.Add("@UserName", SqlDbType.VarChar, 100).Value = Environment.UserName;
            cmd.ExecuteNonQuery();
            cmd.Dispose();

            // Close the connection to the database
            conn.Close();
            conn.Dispose();
        }

        // This function goes through the rows and saves each one to the database
        private Boolean SaveRows()
        {
            // Initialize the return variable
            Boolean returnVal = true;

            // Change the grid focus to end any edits so they are committed to the datatable
            dgvInvoices.CurrentCell = null;

            // Loop through each row in the data table and validate it
            foreach (DataRow row in invoices.Rows)
            {
                if (returnVal == false)
                {
                    continue;
                }
                else
                {
                    // If the row has changed, validate changes
                    if (row.RowState == DataRowState.Modified)
                    {
                        returnVal = Validate(row);
                    }
                }
            }

            // Loop through each row in the data table and save it
            if (returnVal)
            {
                // Loop through each row in the data table
                foreach (DataRow row in invoices.Rows)
                {
                    // If the row has changed, save changes
                    if (row.RowState == DataRowState.Modified)
                    {
                        Save(row);
                    }
                }
            }

            if (returnVal)
            {
                MessageBox.Show("Database updated!");
                LoadInvoices();
            }

            // Return value
            return returnVal;
        }

        // This function validates the data row to make sure it can be saved to the database
        private Boolean Validate(DataRow row)
        {
            // Validate date received
            DateTime dateBilled;
            try
            {
                dateBilled = DateTime.Parse(row["DateBilled"].ToString());
            }
            catch
            {
                MessageBox.Show("Date received is incorrect");
                return false;
            }
            if (dateBilled < DateTime.Parse("1/1/2010"))
            {
                MessageBox.Show("Date received must be on or after 1/1/2010");
                return false;
            }

            // Validate date paid
            DateTime datePaid;
            if (!row["DatePaid"].ToString().Trim().Equals(""))
            {
                try
                {
                    datePaid = DateTime.Parse(row["DatePaid"].ToString());
                }
                catch
                {
                    MessageBox.Show("Date paid is incorrect");
                    return false;
                }
                if (datePaid < dateBilled)
                {
                    MessageBox.Show("Date paid must be on or after date received");
                    return false;
                }
            }

            // Validate amount
            Double amount;
            try
            {
                amount = Double.Parse(row["Amount"].ToString());
            }
            catch
            {
                MessageBox.Show("Amount is incorrect");
                return false;
            }
            if (amount <= 0)
            {
                MessageBox.Show("Amount must be positive");
                return false;
            }

            // Return true
            return true;
        }

        #endregion

        #region Window Events

        // This function marks the column as checked
        private void CheckColumn(String columnName, Boolean checkState)
        {
            // Turn on the ignore change flag to prevent recalculating totals for each row
            ignoreChange = true;

            // Loop through each row in the displayable grid
            foreach (DataRowView viewRow in invoices.DefaultView)
            {
                DataRow row = viewRow.Row;
                row[columnName] = checkState;
                if ((columnName == "Paid") && (checkState == true))
                {
                    row["DoNotPay"] = false;
                }
                if ((columnName == "DoNotPay") && (checkState == true))
                {
                    row["Paid"] = false;
                }
            }

            // Turn off the ignore change flag
            ignoreChange = false;

            // Recalculate the totals
            CalculateTotals();

            // Refresh the grid
            dgvInvoices.Refresh();
        }

        // This function is used to limit the characters input in a date box
        private void Date_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (("/0123456789".Contains(e.KeyChar)) || ((Int32)e.KeyChar == 8))
            {
                e.Handled = false;
            }
            else
            {
                e.Handled = true;
            }
        }

        // This function is called when filters update
        private void FilterTextChanged(object sender, EventArgs e)
        {
            // Build the filter
            if (!ignoreChange)
            {
                String filter = "";
                filter += "CustomerName Like '%" + tbName.Text.Replace("'", "''") + "%' ";
                filter += "And [Contract] Like '%" + tbContract.Text.Replace("'", "''") + "%' ";
                filter += "And PolicyNumber Like '%" + tbPolicy.Text.Replace("'", "''") + "%' ";
                filter += "And Convert(Receipt,System.String) Like '%" + tbReceipt.Text.Replace("'", "''") + "%' ";
                filter += "And IsNull(DateBilled,'1/1/1900') >= '" + dpMinDateBilled.Text + "' ";
                filter += "And IsNull(DateBilled,'1/1/1900') <= '" + dpMaxDateBilled.Text + "' ";
                filter += "And IsNull(DatePaid,'1/1/1900') >= '" + dpMinDatePaid.Text + "' ";
                filter += "And IsNull(DatePaid,'1/1/1900') <= '" + dpMaxDatePaid.Text + "' ";

                // Apply the filter to the table
                invoices.DefaultView.RowFilter = filter;

                // Calculate totals
                CalculateTotals();
            }
        }

        // This function is called when the form is closing
        private void InvoiceEditor_FormClosing(object sender, FormClosingEventArgs e)
        {
            // By default, assume not closing
            e.Cancel = false;

            // Check if changes have been made
            Boolean changed = false;
            foreach (DataRow row in invoices.Rows)
            {
                if (changed)
                {
                    continue;
                }
                else
                {
                    if (row.RowState == DataRowState.Modified)
                    {
                        changed = true;
                    }
                }
            }

            // If changes were made, ask the user if they want to save changes
            if (changed == true)
            {
                // Ask the customer if they want to save changes
                DialogResult choice = MessageBox.Show("Changes have been made to invoices. Do you want to save them?", "Save Changes", MessageBoxButtons.YesNoCancel);
                if (choice == DialogResult.Yes)
                {
                    e.Cancel = !SaveRows();
                }
                else if (choice == DialogResult.Cancel)
                {
                    e.Cancel = true;
                }
            }
        }

        // This function is called when the form is loading
        private void InvoiceEditor_Load(object sender, EventArgs e)
        {
            // Set the window fields to defaults
            ResetFields();

            // Load invoices
            LoadInvoices();

            // Set the window header
            switch (type)
            {
                case 'A':
                    this.Text = "All Invoices";
                    break;
                case 'C':
                    this.Text = "Invoices w/o Customers";
                    break;
                case 'N':
                    this.Text = "Do Not Pay Invoices";
                    break;
                case 'P':
                    this.Text = "Paid Invoices";
                    break;
                case 'U':
                    this.Text = "Unpaid Invoices";
                    break;
                case 'W':
                    this.Text = "Wrong Amount Invoices";
                    break;
            }
        }

        // This function is called when the Do Not Pay flag is clicked
        private void cbDoNotPay_CheckedChanged(object sender, EventArgs e)
        {
            // If the user checked the box, check all of the rows in the grid
            if (!ignoreChange)
            {
                CheckColumn("DoNotPay", cbDoNotPay.Checked);
            }
        }

        // This functions is called when the Paid flag is clicked
        private void cbPaid_CheckedChanged(object sender, EventArgs e)
        {
            // If the user checked the box, check all of the rows in the grid
            if (!ignoreChange)
            {
                CheckColumn("Paid", cbPaid.Checked);
            }
        }

        // This function is called when the Wrong Amount flag is clicked
        private void cbWrongAmt_CheckedChanged(object sender, EventArgs e)
        {
            // If the user checked the box, check all of the rows in the grid
            if (!ignoreChange)
            {
                CheckColumn("WrongAmount", cbWrongAmt.Checked);
            }
        }

        // This function is called when the cell value changes
        private void dgvInvoices_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            // If one of the flag changes, recalculate the totals
            if ((!ignoreChange) && (" 8 9 10 ".Contains(e.ColumnIndex.ToString())))
            {
                // Change focus to end the edit
                dgvInvoices.CurrentCell = dgvInvoices.Rows[e.RowIndex].Cells[0];

                // If the paid flag changes, flip the other one
                if ((e.ColumnIndex == 8) && (Boolean.Parse(dgvInvoices.Rows[e.RowIndex].Cells[8].Value.ToString()) == true))
                {
                    dgvInvoices.Rows[e.RowIndex].Cells[9].Value = false;
                }

                // If the do not pay flag changes, flip the other one
                if ((e.ColumnIndex == 9) && (Boolean.Parse(dgvInvoices.Rows[e.RowIndex].Cells[9].Value.ToString()) == true))
                {
                    dgvInvoices.Rows[e.RowIndex].Cells[8].Value = false;
                }

                dgvInvoices.Refresh();

                CalculateTotals();
            }
        }

        // This function is called when a row in grid is double clicked
        private void dgvInvoices_DoubleClick(object sender, EventArgs e)
        {
            // Get the selected row
            DataRowView row = (DataRowView)dgvInvoices.BindingContext[invoices].Current;
            Int32 InvoiceID;
            try
            {
                InvoiceID = Int32.Parse(row["ID"].ToString().Trim());
            }
            catch
            {
                InvoiceID = 0;
            }

            // Ensure a row was selected
            if (InvoiceID != 0)
            {
                // Display the window for editing this invoice
                Invoice inv = new Invoice(InvoiceID,row["CustomerName"].ToString());
                inv.ShowDialog(this.MdiParent);
            }
        }

        #endregion

        #region Menu Items

        // This function is called when the close button is clicked on the menu
        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Close the form
            this.Close();
        }

        // This function is called when the save button is clicked on the menu
        private void saveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Call the save method
            SaveRows();
        }

        // This function is called when the undo button is clicked on the menu
        private void undoToolStripMenuItem_Click(object sender, EventArgs e)
        {
            // Reset filters
            ResetFields();

            // Reload the grid
            LoadInvoices();
        }

        #endregion
    }
}

最佳答案

我会将您的发票数据加载到数据表中。

您可以使用Binding Source 并将其数据源设置为您的DataTable 的数据源。如果您正在考虑使用 DataGridView,则可以将此对象的数据源设置为绑定(bind)源。

这样做意味着您只需要对内存中的 DataTable 执行筛选,所有更改都会自动波及到您的 DataGridView。

您可以使用 DataView 非常轻松地对 DataTable 执行筛选。

希望这对您有所帮助。

关于c# - 以编程方式更新 DataGridView 中的多行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12362191/

相关文章:

c# - DataGridView 字段值中的货币符号(不是 $)

c# - 如何刷新绑定(bind)到已更新的 Access 数据库表的 DataGridView?

c# - 通过反射获取接口(interface)属性

c# - ASP.NET MVC 混合模式身份验证

c# - 自动调整 Winform 大小 - 打乱控件顺序

c# - 除非添加到表单中,否则动态创建的 datagridview 列不可访问...为什么?

c# - Pdf 与 iText 合并/重叠

c# - 关于继承的域模型问题

C#,mouseClickEvent 不响应鼠标右键单击

C#.NET Winform 按键事件无法取消