2017-02-06 7 views
1

Каков наилучший подход для обработки редактируемых DataGridView (DGV)DataGridView: Каков наилучший подход для обработки редактируемых данных в DataGridView?

Голов:

Что мне нужно достигнуть, независимо от суммы, вводится в колонке суммы, баланс столбец будет обновляться. Вычислить общую сумму, введенную пользователем в DGV, и установить ее в текстовое поле суммы платежа.

enter image description here

Объект Класс:

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 и назовите его по классу собственности

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); 
} 

Заполнение DataGrid с помощью DataSource - Если я заполнил DataGridView, как это, тогда было бы легко отличить строку как объект счета. Но проблема в том, что я должен вручную установить нежелательные столбцы, чтобы они отображались вместо того, чтобы просто выбирать столбцы, которые я хочу показать. Любые предложения будут ценны.

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

enter image description here

Trigger Функция

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(); 
     } 
} 

Пожалуйста, не стесняйтесь задавать вопросы, критиковать любого из моего кода или комментария путаницы, чтобы я мог исправить и улучшить свое объяснение.

ответ

2

Обратите внимание, что в C# вы пишете CamelCase для методов и свойств: GetInvoiceBalance() или AccountName. Далее вместо цикла вы можете установить свойство dataGridView.DataSource. Возможные источники данных - это DataTables и все типы реализации IList, которые я знаю. Таким образом, вы можете сделать следующее:

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

Изменения в вашем источнике данных будут отражены в сетке. Таким образом, вы можете определить поглотитель вашего баланса-собственность как:

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

Так что если вы измените количество, сетка автоматически обновлять баланс вашей суммы + 10. Обратите внимание, что dataGridView.Refresh() требуется возможно.

Вы заметили, что Grid заполнит каждое свойство в виде столбца. Если вы не хотите этого, вы можете добавить столбцы самостоятельно. Вы можете определить их в конструкторе или непосредственно в коде:

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); 

Таким образом, вы можете создать столбцы, необходимые и сетки не будет заполнить столбец для каждого свойства, которое является поведением по умолчанию.

Последний шаг - вычислить общую сумму. Я бы рекомендовал использовать DataSource как можно больше, и пусть представление просто делает просмотр.Ваш 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. Обратите внимание, что вы должны реализовать 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(); 

Это потому, что я думаю, что один конкретный Счет-объект не имеет ничего общего с чтением счетов-фактур. Надеюсь, ты знаешь, что я имею в виду. Чтение не является специфичным для объекта.

Я надеюсь, что это может вам помочь.

+0

Спасибо, это очень поможет мне. –

+0

@ android-guy Приветствую вас :-) – Sebi