DataGridView column footer c#.net winforms

前端 未结 3 959
走了就别回头了
走了就别回头了 2020-12-06 03:16

Is there a way to add a column footer in a datagridview which is not databound? I am using it to take user input for adding inventory. Currently I am using a la

相关标签:
3条回答
  • 2020-12-06 03:45

    I ran into the same problem previously and after a long search I realised;

    1. Winform Datagridview do not support adding footer to it.

    2. I tried adding an extra row that could hold the summary but still did not work out fine.

    3. You can create a user control that has two grids and with the lower grid holding the summary.

    Solution-- enter image description here

    1. My solution that used data binding.(1)-I Create an abstract object Item with (Name, Cost) properties.(2)-I Create a Concrete item i.e ConcItem that inherit Item(3)-I create a footer item i.e FooterItem that also inherits Item(4)-A collection of Items i.e ItemList where you instantiate the footer item.(5) Finally, just before you do data binding call the method that adds the footer item.

      public abstract class Item
      {
        public virtual string Name { get; set; }
        public virtual int Cost { get; set; }
      }
      public  class ConcItem:Item
      {
        public override string Name { get; set; }
        public override int Cost { get; set; }        
      }
      public  class FooterItem:Item 
      {
        public override string Name { get { return "Total"; } }
        public override int Cost { get; set; }
      }
      public class ItemList : List<Item>
      {
        private Item _footer;
      
        public void SetFooter()
        {
          _footer = new FooterItem();            
          foreach (var item in this)
          {
            _footer.Cost += item.Cost;              
          }
          this.Add(_footer);
        }
      }
      
      
      public partial class Form1 : Form
      {
        Item _item;
        ItemList _itemList;
        public Form1()
        {
          InitializeComponent();
          dgv.DataBindingComplete += dgv_DataBindingComplete;
          _itemList = new ItemList();
      
          SetSampleData();
        }
        private void SetSampleData()
        {
          _item = new ConcItem();
          _item.Name = "Book";
          _item.Cost = 250;
          _itemList.Add(_item);
      
          _item = new ConcItem();
          _item.Name = "Table";
          _item.Cost = 500;
          _itemList.Add(_item);
      
          _item = new ConcItem();
          _item.Name = "PC";
          _item.Cost = 700;
          _itemList.Add(_item);
      
          dgv.DataSource = null;
          _itemList.SetFooter();  //Add the footer item b4  data binding
          dgv.DataSource = _itemList;
        }
        void dgv_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
          //If you want to do some formating on the footer row
          int rowIndex = dgv.Rows.GetLastRow(DataGridViewElementStates.Visible);
          if (rowIndex <= 0)
          {
            return;
          }
          dgv.Rows[rowIndex].DefaultCellStyle.BackColor = Color.Red;
          dgv.Rows[rowIndex].DefaultCellStyle.SelectionBackColor = Color.Red;        
          dgv.Rows[rowIndex].DefaultCellStyle.Font = new Font("Microsoft Sans Serif", 12f,    FontStyle.Bold);
        }
      }
      
    0 讨论(0)
  • 2020-12-06 03:53

    There is a better solution. In this solution, every time the cell content changed, the value will be recalculated and displayed.

    My data grid view looks like this.

    In this solution, you can have any number of columns and any number of rows.

    private void updateDataGridViewTotal(DataGridView dgv)
        {
            DataTable dt = (DataTable)dgv.DataSource;
            int lastRow = (dgv.Rows.Count - 1);
            if (dt.Rows[lastRow][0].ToString() == "Total")
            {
                dt.Rows.RemoveAt(lastRow);
            }
            int[] tot = new int[dt.Columns.Count];
            Array.Clear(tot, 0, tot.Length);
    
            foreach (DataRow row in dt.Rows)
            {
                int rowSum = 0;
                for (int i = 1; i < dt.Columns.Count - 1; i++)
                {
                    tot[i] += Convert.ToInt32(row[i]);
                    rowSum += Convert.ToInt32(row[i]);
                }
                row["Total"] = rowSum;
            }
            DataRow newRow = dt.NewRow();
            newRow["Agent"] = "Total";
            for (int i = 1; i < tot.Length; i++)
            {
                newRow[i] = tot[i];
            }
            dt.Rows.Add(newRow);
            dgv.DataSource = dt;
        }
    

    Just pass your datagridview to the function.

    0 讨论(0)
  • 2020-12-06 04:00

    In one of my applications I solved it by taking advantage of NewRow of DataGridView like this.

    using System;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication2
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                this.dataGridView1.CellFormatting += dataGridView1_CellFormatting;
                this.dataGridView1.CellValueChanged += dataGridView1_CellValueChanged;
            }
    
            void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
            {
                if (e.RowIndex != this.dataGridView1.NewRowIndex && e.ColumnIndex == 2)
                {
                    this.dataGridView1.InvalidateRow(this.dataGridView1.NewRowIndex);
                }
            }
    
            void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
            {
                if (e.RowIndex == this.dataGridView1.NewRowIndex)
                {
                    e.CellStyle.Font = new Font(e.CellStyle.Font, FontStyle.Bold);
                    e.CellStyle.ForeColor = Color.Red;
                    switch (e.ColumnIndex)
                    {
                        case 0:
                            e.Value = "Total";
                            break;
    
                        case 2:
                            var sum = 0.0d;
                            for (int i = 0; i < this.dataGridView1.NewRowIndex; i++)
                            {
                                var value = this.dataGridView1[2, i].Value;
                                if (value is double)
                                {
                                    sum += ((double)value);
                                }
                            }
                            e.Value = Math.Round(sum, 2);
                            break;
                        // Single line version of case 2 would be
                        // e.Value = this.dataGridView1.Rows.Cast<DataGridViewRow>().Where(a => a.Index != a.DataGridView.NewRowIndex).Select(a => (double)a.Cells[2].Value).Sum().ToString("N2");
                    }
                }
            }
    
        }
    }
    

    Here is live screenshot of how it works.

    0 讨论(0)
提交回复
热议问题