I'm working on creating a C# windows forms application to manage invoices and I need some assistance to see if I'm heading in the right direction. I need to:
I know that I will probably need to use the DataGridView
to achieve this but I'm not sure what to bind it to. This article from MSDN looks promising but I'm not sure how to fill the BindingList
class from the database table. The article is calling an Add method to add individual rows but I would want to be able to add all the rows at once (or at least have a loop there to add them all with a couple lines of code).
I assume that is possible with the BindingList
class. Also, does the BindingList
class support row filtering, similar to the RowFilter
property of the DataView
class? There's another article on StackOverflow that references this class but it didn't give details on how to fill the BindingList
from the database, how to apply a filter to it, or how to pragmatically change rows in the DataGridView
.
The MSDN article appears that changes aren't made to the DGV itself but rather the underlying data source and then through the INotifyPropertyChanged
interface the DGV is updated. I have some idea of what needs to play out, I just need a little help arranging the pieces. All help is appreciated!
I figured this out and the code is below as an example for anyone else that needs help. This may or may not be the best way to do it, but it worked for me.
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
}
}
I would load your Invoices Data into a DataTable.
You can use a Binding Source and set its datasource to that of your DataTable. If you are looking at using a DataGridView you then set the datasource for this object to the binding source.
Doing this will mean you only ever need to perform a filter on the DataTable in memory, and all changes will automatically ripple through to your DataGridView.
You can use DataView's to perform the filters on the DataTable very easily.
Hope this helps.
During databinding event. there is a Event argument that contains the data to be binded... You can set the values in this argument and it will be automatcaly set into dataGridView
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.