簡體   English   中英

DataGridView:處理DataGridView中的可編輯數據的最佳方法是什么?

[英]DataGridView: What is the best approach to handle Editable Data in DataGridView?

什么是處理可編輯DataGridView(DGV)的最佳方法

目標:

我需要實現的是在金額列中輸入任何金額,余額列將被更新。 計算用戶在DGV中輸入的總金額,並將其設置為付款金額文本框。

在此處輸入圖片說明

對象類別:

class Invoice
{
    public int id { get; set; }
    public int invoice_id { get; set; }
    public string invoicenumber { get; set; }
    public DateTime date { get; set; }
    public DateTime due_date{ get; set; }
    public decimal total_gross { get; set; }
    public bool is_service { get; set; }
    public int customer_id { get; set; }
    public List<Invoice> invoices = new List<Invoice>();
    // and other properties

    public decimal get_invoice_balance(decimal payment_amount)
    {
        return total_gross - payment_amount;
    }

    public List<Invoice> read(string where_query)
    {
        try
        {
            string query = "SELECT invoice.id as id,invoicenumber,name,date,due_date,account_name,remarks,total_gross,invoice_id FROM invoice ";
            query += "LEFT JOIN customer ON customer.customer_id = invoice.customer_id ";
            query += "LEFT JOIN account ON account.account_id = invoice.ar_account_id "; 

            conn.cmd.Parameters.AddWithValue("@company_id", Variables.Company_ID);

            if (where_query != null && where_query.Length > 0)
            {
                query += where_query;
            }else
            {
                query += "WHERE invoice.company_id = @company_id ";
            }

            query += "ORDER BY invoice_id ";

            conn.OPEN(query);

            while (conn.reader.Read())
            {
                Invoice invoice = new Invoice();
                invoice.id = Int32.Parse(conn.reader["id"].ToString());
                invoice.invoice_id = Int32.Parse(conn.reader["invoice_id"].ToString());
                invoice.invoicenumber = (string)conn.reader["invoicenumber"];
                invoice.customer_name = Global_Functions.object_to_string(conn.reader["name"]);
                invoice.date = Convert.ToDateTime(conn.reader["date"]).Date;
                invoice.due_date = Convert.ToDateTime(conn.reader["due_date"]).Date;
                invoice.ar_account_name = Global_Functions.object_to_string(conn.reader["account_name"]);
                invoice.remarks = Global_Functions.object_to_string(conn.reader["remarks"]);
                invoice.total_gross = (decimal)conn.reader["total_gross"];

                invoices.Add(invoice);
            }

            conn.CLOSE();

            return invoices;

        } catch (Exception err)
        {
            Global_Functions.open_error_dialog(err.Message.ToString());
            return invoices;
        }
    }      

}

填充DataGridView-在DataGridView中手動添加了列,並根據class屬性對其進行了命名

List<Invoice> invoices = new Invoice().read(null);

foreach (Invoice invoice_item in invoices)
{
            DataGridViewRow row = (DataGridViewRow)dgv_invoices.Rows[0].Clone();
            row.Cells[0].Value = invoice_item.id;
            row.Cells[1].Value = invoice_item.invoicenumber;
            row.Cells[2].Value = invoice_item.date;
            row.Cells[3].Value = invoice_item.due_date;
            row.Cells[4].Value = invoice_item.total_gross;
            row.Cells[5].Value = invoice_item.get_invoice_balance(Convert.ToDecimal(row.Cells[6].Value));
            row.Cells[6].Value = 0;
            row.Tag = invoice_item;
            dgv_invoices.Rows.Add(row);
}

用DataSource填充DataGrid-如果我這樣填充DataGridView,則將行輕松轉換為發票對象會很容易。 但是問題是我必須手動將不需要的列設置為不顯示,而不僅僅是選擇我要顯示的列。 任何建議將不勝感激。

List<Invoice> invoices = new Invoice().read(null);
dgv_invoices.DataSource = invoices;

在此處輸入圖片說明

觸發功能

private void dgv_invoices_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
      if(dgv_invoices.Columns[e.ColumnIndex].Name == "Amount")
      {                       
            // Cast the Datagridrow into an Object Invoice, this works if i populate the datagridview with dgv_invoices.Datasouce = invoices;
            Invoice invoice = (Invoice)dgv_invoices.CurrentRow.DataBoundItem;


            // use the instance to compute, (Note: I need to put the computations in the class so it would be easy to reuse the code and manage it)
            decimal balance = invoice.get_invoice_balance("Amount inputted in Amount Cell")

            // Update the Cell in Column
            dgv_invoices.CurrentRow.Cell = balance;

            // Update Payment Amount based on the list - Pseudo
            tx_payment_amount.Text = function_to_compute_total();
      }
 }

請隨時提出問題,批評我的任何代碼或評論任何混亂,以便我糾正和改進我的解釋。

注意,在C#中,您為方法和屬性編寫了CamelCase: GetInvoiceBalance()AccountName 此外,可以設置Property dataGridView.DataSource而不是循環。 到目前為止,我知道的可能的數據源是DataTables和所有類型的IList實現。 因此,您可以執行以下操作:

List<Invoice> invoices = new Invoice().Read(null);
dataGridView.DataSource = invoices;

對數據源的更改將反映到網格中。 因此,您可以定義您的Balance-Property的吸氣劑,例如:

public int Balance {get {return Amount + 10;}}

因此,如果您編輯金額,則網格會自動將“余額”更新為“金額+ 10”。請注意,可能需要dataGridView.Refresh()

您注意到網格將每個屬性填充為一列。 如果您不想這樣做,則可以自己添加列。 您可以在Designer中定義它們,也可以直接在代碼中定義它們:

DataGridViewColumn col = new DataGridViewColumn();
col.DataPropertyName = nameof(Invoice.Amount); //This binds the value to your column
col.HeaderText = "Amount";
col.Name = "Amount";
dgViewStudents.Columns.Add(col);

因此,您可以創建所需的列,並且Grid不會為每個屬性填充一個列,這是默認行為。

最后一步是計算總量。 我建議盡可能多地使用DataSource,並讓視圖只做視圖工作。 您的數據源是您創建的List<Invoice> 因此,將INotifyPropertyChanged添加到您的Invoice-Class將是一個不錯的方法。

class Invoice : INotifyPropertyChanged
{
    private int _amount;

    public event PropertyChangedEventHandler PropertyChanged;

    public int Amount 
    {
       get{return _amount;}
       set
       {
          _amount = value;
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Amount)))
       }
    }
}

您應該為每個媒體資源執行此操作。 這個接口有些樣板,所以如果您有興趣更好地使用PostSharp ,可以使用它。

現在,您可以將List<Invoice>更改為BindingList<Invoice>並將其應用於網格。 如果某些元素發生更改,則BindingList允許您得到通知。 為此注冊ListChanged-Event。 請注意,必須實現INotifyPropertyChanged才能收到有關元素更改的通知。 否則,您只會收到有關新項目或已刪除項目的通知。

 BindingList<Invoice> invoices = new Invoice.Read(null);
 invoices.ListChanged += Invoice_ListChanged;

 private void Test_ListChanged(object sender, ListChangedEventArgs e)
 {
    if (e.ListChangedType == ListChangedType.ItemChanged)
    {
       //Calculate Amount and populate to TextBox (invoices is your DataSource)
       textBoxSum.Text = invoices.Sum(invoice => invoice.Amount);
    }
 }

此外,我建議您制作Read(); 靜態的。 因此,您可以這樣稱呼它:

Invoice.Read();

代替:

new Invoice.Read();

這是因為我認為一個特定的發票對象與閱讀發票無關。 我希望你明白我的意思。 閱讀不是特定於對象的。

希望對您有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM