[英]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.