I have a DataGridView in which I want to sum up values from two different columns into a third column.
Example DataGridView:
A B Total
1 2 3
25 35 60
5 -5 0
I want to add (A+B) in total, just after entering values in A & B column or leaving current row. And also want to set Total Column as ReadOnly.
You can do that on CellValidatedEvent and you can apply the same method to RowValidated:
private void dataGridView_CellValidated(object sender, DataGridViewCellEventArgs e) {
if (e.RowIndex > -1) {
DataGridViewRow row = dataGridView.Rows[e.RowIndex];
string valueA = row.Cells[columnA.Index].Value.ToString();
string valueB = row.Cells[columnB.Index].Value.ToString();
int result;
if (Int32.TryParse(valueA, out result)
&& Int32.TryParse(valueB, out result)) {
row.Cells[columnTotal.Index].Value = valueA + valueB;
}
}
}
You can set column to ReadOnly in the designer, or like this:
dataGridView.Columns["Total"].ReadOnly = true
You could easily do this
But you should have a dataset or localdatabase connection like SQL
I will assume that you got it and name it
Totaldataset.
Easily done I know it's too late answer but maybe it help some new readers.
Datacolumn column = new Datacolumn ();
column.Columnname = "Total";
Totaldataset.Tables[0].Columns.["Total"].Expression = "a+b";
This is a working example:
public partial class Form1 : Form
{
DataGridView _calcDataGridView;
public Form1()
{
InitializeComponent();
_calcDataGridView = new DataGridView();
this.Controls.Add(_calcDataGridView);
_calcDataGridView.Dock = DockStyle.Fill;
_calcDataGridView.Name = "CalcDataGridView";
_calcDataGridView.CellEndEdit += Calculate;
var aColumn = new DataGridViewTextBoxColumn();
aColumn.Name = "AColumn";
aColumn.HeaderText = "A";
_calcDataGridView.Columns.Add(aColumn);
var bColumn = new DataGridViewTextBoxColumn();
bColumn.Name = "BColumn";
bColumn.HeaderText = "B";
_calcDataGridView.Columns.Add(bColumn);
var totalColumn = new DataGridViewTextBoxColumn();
totalColumn.Name = "TotalColumn";
totalColumn.HeaderText = "Total";
totalColumn.ReadOnly = true;
_calcDataGridView.Columns.Add(totalColumn);
}
private void Calculate(object sender, DataGridViewCellEventArgs e)
{
object a = _calcDataGridView.CurrentRow.Cells["AColumn"].Value;
object b = _calcDataGridView.CurrentRow.Cells["BColumn"].Value;
double aNumber = 0;
double bNumber = 0;
if (a != null)
aNumber = Double.Parse(a.ToString());
if (b != null)
bNumber = Double.Parse(b.ToString());
_calcDataGridView.CurrentRow.Cells["TotalColumn"].Value = aNumber + bNumber;
}
}
If U r using data binding using Eval
than U can just create a method there and on that method just sum those two values.
Like
For Column A
<ItemTemplate>
<%# Eval("A")%>
</ItemTemplate>
for column B
<ItemTemplate>
<%# Eval("B")%>
</ItemTemplate>
For Total
<ItemTemplate>
<%# GetTotal(Eval("A"),Eval("B")) %>
</ItemTemplate>
For total method
private string GetTotal(object A,object B)
{
return (A+B).ToString();
}
hope this will help you.
Related
I have a DataGridView which is based on a DataSet from a data base referenced by a BindingSource. In the DataSet there is an ID as primary key. Further there is another field in the DataSet containing an BuddyID referencing to another row of the same table. And a field containing a name of the element.
In the DataGridView there is the DataGridViewTextboxColumn with the name and DataGridViewComboboxColumn where you can select the Name of another element to change the BuddyID, reverencing by another BindingSource to the same DataSet. But that don't work like I would have it.
When you have two elements as buddy to each other and you want to set the IDs, then the BuddyID of the other element is changed to the same value too. Although I don't change the other ComboBox the value is changing! Maybe it's a problem of the combo box, but I have no idea about what to do to fix that. Maybe anyone of yours?
Edit: both (buddy) elements have the same name appearing in the combo box
Code generated by the designer - unluckily with name "text" instead of "combo":
private System.Windows.Forms.DataGridViewComboBoxColumn idBuddyDataGridViewTextBoxColumn;
private System.Windows.Forms.DataGridViewComboBoxColumn idB uddyDataGridViewTextBoxColumn;
//
// idBuddyDataGridViewTextBoxColumn
//
this.idBuddyDataGridViewTextBoxColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
this.idBuddyDataGridViewTextBoxColumn.DataPropertyName = "IdBuddy";
this.idBuddyDataGridViewTextBoxColumn.DataSource = this.komponentenBuddyBindingSource;
this.idBuddyDataGridViewTextBoxColumn.DisplayMember = "Komponentenname";
this.idBuddyDataGridViewTextBoxColumn.HeaderText = "Buddy";
this.idBuddyDataGridViewTextBoxColumn.Name = "idBuddyDataGridViewTextBoxColumn";
this.idBuddyDataGridViewTextBoxColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True;
this.idBuddyDataGridViewTextBoxColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic;
this.idBuddyDataGridViewTextBoxColumn.ValueMember = "Id";
this.idBuddyDataGridViewTextBoxColumn.Width = 62;
Code for the DataGridView by designer:
private System.Windows.Forms.DataGridView dgvKomponenten;
this.dgvKomponenten = new System.Windows.Forms.DataGridView();
((System.ComponentModel.ISupportInitialize)(this.dgvKomponenten)).BeginInit();
//
// dgvKomponenten
//
this.dgvKomponenten.AllowUserToDeleteRows = false;
this.dgvKomponenten.AutoGenerateColumns = false;
this.dgvKomponenten.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dgvKomponenten.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.komponentennameDataGridViewTextBoxColumn,
... (10 other columns) ...
this.idBuddyDataGridViewTextBoxColumn});
this.dgvKomponenten.DataSource = this.komponentenBindingSource;
this.dgvKomponenten.Dock = System.Windows.Forms.DockStyle.Fill;
this.dgvKomponenten.Location = new System.Drawing.Point(0, 0);
this.dgvKomponenten.Name = "dgvKomponenten";
this.dgvKomponenten.Size = new System.Drawing.Size(452, 612);
this.dgvKomponenten.TabIndex = 9;
this.dgvKomponenten.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvKomponenten_CellValueChanged);
this.dgvKomponenten.DataError += new System.Windows.Forms.DataGridViewDataErrorEventHandler(this.dgvKomponenten_DataError);
this.dgvKomponenten.RowEnter += new System.Windows.Forms.DataGridViewCellEventHandler(this.dgvKomponenten_RowEnter);
((System.ComponentModel.ISupportInitialize)(this.dgvKomponenten)).EndInit();
And some called code by myself:
private void dgvKomponenten_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
DataGridView dgvChanged = ((DataGridView)sender);
FilteredTypeDataGridViewComboBoxCell ftdgvcbcSubtyp;
if (null != dgvChanged.Columns["idTypDataGridViewTextBoxColumn"])
{
if (e.ColumnIndex == dgvChanged.Columns["idTypDataGridViewTextBoxColumn"].Index)
{
ftdgvcbcSubtyp = (FilteredTypeDataGridViewComboBoxCell)dgvChanged.Rows[e.RowIndex].Cells["idSubtypDataGridViewTextBoxColumn"];
ftdgvcbcSubtyp.InitCellFilter(e.RowIndex);
if (!ftdgvcbcSubtyp.Items.Contains(ftdgvcbcSubtyp.Value))
{
ftdgvcbcSubtyp.Value = 0;
}
}
}
}
You're right; it appears the combo used in the DGV has a bug where it case insensitively looks up the chosen item based on the display text.. If you have 5,"John" or even 5,"john" you can never select it, because choosing it always finds/sets the selection to the first John (the one with id 1)
This is the best workaround I've been able to come up with:
public class Buddy {
public string Name { get; set; }
public int Id { get; set; }
}
public Form1(string s1 = null)
{
InitializeComponent();
dataSet1.People.AddPeopleRow(1, "John", 1);
dataSet1.People.AddPeopleRow(2, "Mary", 1);
dataSet1.People.AddPeopleRow(3, "Mark", 1);
dataSet1.People.AddPeopleRow(4, "Luke", 1);
dataSet1.People.AddPeopleRow(5, "John", 1);
var b = new BindingList<Buddy>();
var h = new Dictionary<string, int>();
foreach (var r in dataSet1.People)
{
if (!d.TryGetValue(r.Name.ToLower(), out int x))
x = 0;
b.Add(new Buddy { Name = r.Name + (x > 0 ? new string('\0', x) : ""), Id = r.Id });
d[r.Name.ToLower()] = x + 1;
}
buddyBindingSource.DataSource = b;
peopleBindingSource.DataSource = dataSet1.People;
}
Namely, we zip through the list of people building a new list of name/id pairs to show in our combo. Every time we hit a name we've seen before, we add an increasing number of NUL characters onto the end of the name. They don't show in the combo, but they permit the text to be different, so that selecting the 5th John really does select that one, not the first one.
I'm new at coding and I'm having a bit of a problem when trying to multiply a summed value from a DataGridView.
Basically, what I want to do is to sum all the values of a DataGridView column into a textbox and then multiply it by the value from another textbox.
So far I've been able to sum all the values from de DGV buy cant seem to figure out how to multiply it with the other textbox.
My code is as follows:
private void BtAgregar_Click(object sender, EventArgs e)
{
if (this.DgvBuscador.DataSource != null)
{
this.DgvCarrito.DataSource = null;
}
else
{
this.DgvCarrito.Rows.Clear();
}
for (int i = 0; i < DgvBuscador.SelectedRows.Count; i++)
{
int index = DgvCarrito.Rows.Add();
DgvCarrito.Rows[index].Cells[0].Value = DgvBuscador.SelectedRows[i].Cells[0].Value.ToString();
DgvCarrito.Rows[index].Cells[1].Value = DgvBuscador.SelectedRows[i].Cells[1].Value.ToString();
DgvCarrito.Rows[index].Cells[2].Value = DgvBuscador.SelectedRows[i].Cells[2].Value.ToString();
DgvCarrito.Rows[index].Cells[3].Value = DgvBuscador.SelectedRows[i].Cells[3].Value.ToString();
DgvCarrito.Rows[index].Cells[4].Value = DgvBuscador.SelectedRows[i].Cells[4].Value.ToString();
DgvCarrito.Rows[index].Cells[5].Value = DgvBuscador.SelectedRows[i].Cells[5].Value.ToString();
DgvCarrito.Rows[index].Cells[6].Value = DgvBuscador.SelectedRows[i].Cells[6].Value.ToString();
}
TbTotal.Text = (from DataGridViewRow row in DgvCarrito.Rows
where row.Cells[6].FormattedValue.ToString() != string.Empty
select Convert.ToInt32(row.Cells[6].FormattedValue)).Sum().ToString();
}
i've tried a different method that i've wanted and it worked.
TbTotal.Text = (from DataGridViewRow row in DgvCarrito.Rows
where row.Cells[6].FormattedValue.ToString() != string.Empty
select Convert.ToInt32(row.Cells[6].FormattedValue) * Convert.ToInt32(TbNoches.Text)).Sum().ToString();
here's another code that works better for what i wanted. now when i add the selected row from one DGV to another DGV, the column 6 (which is the vale) gets multiplied by the number of days from the textbox that calculates the date range.
for (int i = 0; i < DgvBuscador.SelectedRows.Count; i++)
{
int index = DgvCarrito.Rows.Add();
DgvCarrito.Rows[index].Cells[0].Value = DgvBuscador.SelectedRows[i].Cells[0].Value.ToString();
DgvCarrito.Rows[index].Cells[1].Value = DgvBuscador.SelectedRows[i].Cells[1].Value.ToString();
DgvCarrito.Rows[index].Cells[2].Value = DgvBuscador.SelectedRows[i].Cells[2].Value.ToString();
DgvCarrito.Rows[index].Cells[3].Value = DgvBuscador.SelectedRows[i].Cells[3].Value.ToString();
DgvCarrito.Rows[index].Cells[4].Value = DgvBuscador.SelectedRows[i].Cells[4].Value.ToString();
DgvCarrito.Rows[index].Cells[5].Value = DgvBuscador.SelectedRows[i].Cells[5].Value.ToString();
DgvCarrito.Rows[index].Cells[6].Value = (Convert.ToInt32(DgvBuscador.SelectedRows[i].Cells[6].Value) * Convert.ToInt32(TbNoches.Text)).ToString();
}
TbTotal.Text = (from DataGridViewRow row in DgvCarrito.Rows
where row.Cells[6].FormattedValue.ToString() != string.Empty
select Convert.ToInt32(row.Cells[6].FormattedValue)).Sum().ToString();
hello experts help please, i have two form in my project and one of those form1 have dataGridView and i want to update the gridview according to text value from form 2,
i had done updating dgv but all row updated on button click event
ex. i have 4 rows different description and cell value after click event
all those 4 rows updating to 1 value.
Form 1
dgv cellmouseclick event
if (e.RowIndex >= 0)
{
DataGridViewRow row = dataGridView2.Rows[e.RowIndex];
_choosenPart = row.Cells[0].Value.ToString();
_choosenQty = row.Cells[2].Value.ToString();
_choosenPrice = row.Cells[4].Value.ToString();
_choosenAmount = row.Cells[5].Value.ToString();
_choosenTotal = row.Cells[7].Value.ToString();
}
FrM_Edit EditGV = new FrM_Edit(this);
EditGV.Show();
In form 2
//constructor
Form F2_main = null;
public FrM_Edit(Form DgVForm1)
{
F2_main=DgVForm1;
InitializeComponent();
}
button click event
r2main_choosenPart = textBox1.Text;
r2main_choosenQty = textBox2.Text;
r2main_choosenPrice = textBox3.Text;
r2main_choosenAmount = textBox4.Text;
r2main_choosenTotal = textBox5.Text;
DataGridView Main_dg = (DataGridView)F2_main.Controls["dataGridView2"];
for (int i = 0; i < Main_dg.Rows.Count; i++)
{
Main_dg.Rows[i].Cells[0].Value = r2main_choosenPart;
Main_dg.Rows[i].Cells[2].Value = r2main_choosenQty;
Main_dg.Rows[i].Cells[4].Value = r2main_choosenPrice;
Main_dg.Rows[i].Cells[5].Value = r2main_choosenAmount;
Main_dg.Rows[i].Cells[7].Value = r2main_choosenTotal;
}
this.Close();
//this for loop takes all rows of your DataGridView. And it is normal that you see that all rows are changing because for all rows, you apply the same code.
DataGridView Main_dg = (DataGridView)F2_main.Controls["dataGridView2"];
for (int i = 0; i < Main_dg.Rows.Count; i++)
{
Main_dg.Rows[i].Cells[0].Value = r2main_choosenPart;
Main_dg.Rows[i].Cells[2].Value = r2main_choosenQty;
Main_dg.Rows[i].Cells[4].Value = r2main_choosenPrice;
Main_dg.Rows[i].Cells[5].Value = r2main_choosenAmount;
Main_dg.Rows[i].Cells[7].Value = r2main_choosenTotal;
}
Instead, you should update only the row that you want to updaate.
You can use differents methods.
For exemple:
for (int i = 0; i < Main_dg.Rows.Count; i++)
{
if( Main_dg.Rows[i].Cells[0].Value == "valueToChange") //Checking an ID or other value.
{
Main_dg.Rows[i].Cells[0].Value = r2main_choosenPart;
Main_dg.Rows[i].Cells[2].Value = r2main_choosenQty;
Main_dg.Rows[i].Cells[4].Value = r2main_choosenPrice;
Main_dg.Rows[i].Cells[5].Value = r2main_choosenAmount;
Main_dg.Rows[i].Cells[7].Value = r2main_choosenTotal;
break; // To break after finding the row that you are looking for.
}
}
Or
for (int i = 0; i < Main_dg.Rows.Count; i++)
{
if(i == 2) //to update the third row of the grid.
{
Main_dg.Rows[i].Cells[0].Value = r2main_choosenPart;
Main_dg.Rows[i].Cells[2].Value = r2main_choosenQty;
Main_dg.Rows[i].Cells[4].Value = r2main_choosenPrice;
Main_dg.Rows[i].Cells[5].Value = r2main_choosenAmount;
Main_dg.Rows[i].Cells[7].Value = r2main_choosenTotal;
break; // To break after finding the row that you are looking for.
}
}
Or you can use your DataGridViews selected row to update.
I'm using devexpress XtraGrid control. My problem is the following: I want to get the sum of the first column, and then the second column. I eventually want to subtract the sum of the first column of the sum of the second columns and to display the grid in the footer ...
Sum1Columns - Sum2Columns = balance
And then show balance on data grid control - footer (below the 1column)
dgvVIEW.Columns(1).Name = "PROMDUGU"
dgvVIEW.Columns(1).Caption = "1COLUMN"
dgvVIEW.Columns(1).Visible = True
dgvVIEW.Columns(1).DisplayFormat.FormatType = FormatType.Numeric
dgvVIEW.Columns(1).DisplayFormat.FormatString = "c2"
dgvVIEW.Columns(1).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Custom
dgvVIEW.Columns(1).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
dgvVIEW.Columns(1).SummaryItem.DisplayFormat = "SUM= {0:n2}"
dgvVIEW.Columns(2).Name = "PROMPOTR"
dgvVIEW.Columns(2).Caption = "2COLUMN"
dgvVIEW.Columns(2).Visible = True
dgvVIEW.Columns(2).DisplayFormat.FormatType = FormatType.Numeric
dgvVIEW.Columns(2).DisplayFormat.FormatString = "c2"
dgvVIEW.Columns(2).SummaryItem.SummaryType = DevExpress.Data.SummaryItemType.Sum
dgvVIEW.Columns(2).SummaryItem.DisplayFormat = "Sum= {0:n2}"
Add another summary field to 2nd column and set its type to custom.
dgvVIEW.Columns(2).Summary.Add(new GridColumnSummaryItem(SummaryItemType.Custom, "customBalance", "Balance= {0:c2}"));
Then handle CustomSummaryCalculate event.
private void dgvVIEW_CustomSummaryCalculate(object sender, CustomSummaryEventArgs e) {
if (e.SummaryProcess == CustomSummaryProcess.Start) {
this.sum1 = 0; // <--- class member !
this.sum2 = 0; // <--- class member !
return;
}
if (e.SummaryProcess == CustomSummaryProcess.Calculate) {
if (e.Item.FieldName == "PROMDUGU" {
this.sum1 += Convert.ToDecimal(e.FieldValue);
return;
}
if (e.Item.FieldName == "PROMPOTR" {
this.sum2 += Convert.ToDecimal(e.FieldValue);
return;
}
return;
}
if (e.SummaryProcess == CustomSummaryProcess.Finalize && e.Item.FieldName == "customBalance") {
e.TotalValue = sum1 - sum2;
}
}
I'm trying to use an ajax panel to add keep multiple images added to table cells dynamically. Thing is when I add the second image, the first one dissapears.
Its really just a silly example to try and get ajax controls working for another project.
I'm putting an image of Bill Gates in row 3, column 3 and an image of Steve Jobs in row 1, column 5. I have a button to place each image.
I can't seem to get both to display at the same time.
I have written a function to generate the cell id (GenerateTableCellID), as I've been told I would need to to this. Also there is a function to extract the cell and row in a tuple (GetColumnAndRow).
I'm not sure how to use a Session object to save the data. I thought using AJAX would be the answer, though I think I'm missing a major aspect of it.
<asp:Content ContentPlaceHolderID="MainContent" runat="server">
<asp:UpdatePanel ID="UpdatePanel2" runat="server">
<ContentTemplate>
<div id="tablePlaceHolder" runat="server"></div>
<asp:Button ID="tblButton2" runat="server" Text="Add Steve Jobs" OnClick="tblButton_Click_Jobs" />
<asp:Button ID="tblButton" runat="server" Text="Add Bill Gates" OnClick="tblButton_Click" />
</ContentTemplate>
</asp:UpdatePanel>
</asp:Content>
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Page_Init(object sender, EventArgs e)
{
int tableSize = 5;
var t = new HtmlTable();
t.ID = "myTable";
var placeHolderURL = "http://wiki.tripwireinteractive.com/images/4/47/Placeholder.png";
for (int r = 0; r < tableSize; r++)
{
var tableRow = new HtmlTableRow();
tableRow.ID = "row_" + r.ToString();
for (int c = 0; c < tableSize; c++)
{
var tableCell = new HtmlTableCell();
var id = GenerateTableCellID(r, c);
tableCell.ID = id;
tableCell.Height = "20";
tableCell.Width = "20";
tableCell.InnerHtml = string.Format("<img src='{0}' width='20' height='20' />", placeHolderURL);
tableRow.Controls.Add(tableCell);
}
t.Controls.Add(tableRow);
}
tablePlaceHolder.Controls.Add(t);
}
protected void tblButton_Click(object sender, EventArgs e)
{
int c =2;
int r = 2;
var id = GenerateTableCellID(c, r);
var image = GenerateImage("http://www.mnn.com/sites/default/files/billgates.jpg");
var cell = (HtmlTableCell)UpdatePanel2.FindControl(id);
cell.InnerHtml = "";
cell.Controls.Add(image);
}
protected void tblButton_Click_Jobs(object sender, EventArgs e)
{
int c = 4;
int r = 0;
var id = GenerateTableCellID(c, r);
var image = GenerateImage("http://images.boomsbeat.com/data/images/full/209/jobs-jpg.jpg");
var cell = (HtmlTableCell)UpdatePanel2.FindControl(id);
cell.InnerHtml = "";
cell.Controls.Add(image);
}
protected Image GenerateImage(string url)
{
var image = new Image();
image.ImageUrl = url;
image.Width = 20;
image.Height = 20;
return image;
}
protected string GenerateTableCellID(int c, int r)
{
return "column_" + c.ToString() + "_row_" + r.ToString();
}
protected Tuple<int, int> GetColumnAndRow(string tableCellID)
{
string[] splitString = tableCellID.Split('_');
int column, row;
if (Int32.TryParse(splitString[1], out column) && Int32.TryParse(splitString[3], out row))
{
return new Tuple<int, int>(column, row);
}
else
{
return null;
}
}
It is because at every update you clear the html present before by cell.InnerHtml = ""; remove this and try
protected void tblButton_Click_Jobs(object sender, EventArgs e)
{
int c = 4;
int r = 0;
var id = GenerateTableCellID(c, r);
var image = GenerateImage("http://images.boomsbeat.com/data/images/full/209/jobs-jpg.jpg");
var cell = (HtmlTableCell)UpdatePanel2.FindControl(id);
//cell.InnerHtml = "";
cell.Controls.Add(image);
}
As mentioned on the Page LifyCycle your table is created everytime when you do reload page (does not matter is this postback or not). Also you could read this post. In other words, it is not proper way store your data in the dynamic generated controls, because you lose your data on page load.
But if it is necessary for you could use AJAX methods ($.get and $.post, not UpdatePanel) to get data from the backend and add this to generated control on the client side