I have a gridview in winforms which displays bill details. There is a column named total. I created a label with a text "0". Then I used a for loop to get the sum of total column in labels text property.
decimal tot1 = 0;
for (int i = 0; i < dgv_SaleReport.RowCount - 1; i++)
{
tot1 += Convert.ToDecimal(dgv_SaleReport.Rows[i].Cells[7].Value);
}
label_Total1SaleReport.Text = tot1.ToString();
But this code is not working. I added same code in other menu items datagridview and it's working. Right now, I have a tabcontrol which has 4 tabs. In all these 4 tabs dgv the code is not working. Can't just figure it out.
Related
I am trying to use a for loop to iterate through my listBox1 on my motherForm to properly addY values for all entries in my listBox1 to my chart on the second form? The listBox1 entries are dynamic and the chart should respond accordingly if more entries are added.
The chart will correctly generate the columns on the x axis for the number of entries in the listBox1, but all columns have the same y axis value (only pulling the first entry instead of each one dynamically). The code is listed below.
private void Chart_Load(object sender, EventArgs e)
{
for (int i = 1; i <= motherForm.listBox1.Items.Count; i++)
this.chart1.Series["Minutes"].Points.AddY(Double.Parse(motherForm.listBox1.Items[0].ToString()));
}
You just have to use the i variable for the items.
for (int i = 0; i < motherForm.listBox1.Items.Count; i++)
this.chart1.Series["Minutes"].Points.AddY(motherForm.listBox1.Items[i]);
my winForms app has a tab control which consists of two tabs (tab1 & tab2). In tab2 data is fetched in a datagridview fron a database(Product infomations).
In tab1, I've a combobox [sales analyse]which makes a user to select an option.
I now want to get access to tab2 from tab1 on cb selection, displaying me a regional sales information from the data in tab2 datagrid.
Is it possible? I don't really know wher to start
tab1 image
tab2
Expectation:
if the combobox in tab1 is selected, it should then look through the datagridview in tab2 where the (regions) North, East, West ect are and then sum the sale 13, sales 14 .. and display in the textBoxes respectively.
As your controls all sit in one Form their methods can all reference each other without any additional help.
So you can write in the SelectedIndexChanged of the ComboBox cbAnalyse
cbAnalyse_SelectedIndexChanged(object sender, EventArgs e)
{
if (cbAnalyse.SelectedItem.ToStringndex == "Sales Analysis"
{
someTextbox1.Text = ColumnSum(yourDataGridView, someColumn1) + "$";
someTextbox2.Text = ColumnSum(yourDataGridView, someColumn2) + "$";
}
This uses a small helper function, which sums up all values from one column in a DataGridView:
decimal ColumnSum(DataGridView dgv, int columnIndex)
{
decimal sum = 0m;
for (int row = 0; row < DGV.Rows.Count; row++)
if (DGV[columnIndex, row].Value != null) sum += Convert.ToDecimal(DGV[1, row].Value);
return sum;
}
Folks often run into problems when they need to refer to controls that are not sitting in either the same Form but in a 2nd, 3rd etc Form. Or when they are part of a Usercontrol, which is a custome container for holding controls.
In both cases those controls are by default private members of the other Forms or of the UserObject.
In these cases one needs to create some kind of public accessor to them, usually by a Property. And in the case of Forms, one also need to provide a reference to the other forms, often stored when opening them.
In this case, the 2nd Form often also needs a back-refrence to the 1st Form; this is often pass in in the constructor.
But in your case none of these complications matter. All you need is the patience to wire up all those TextBoxes ;-)
Update: As you also seem to have a problem getting the intermediate sums and need to allow for repeating regions in the rows of Tab 2, you also want to use a function that will calculate with a where clause:
decimal ColumnSumWhere(DataGridView dgv, int columnIndex, string region)
{
decimal sum = 0m;
for (int row = 0; row < DGV.Rows.Count; row++)
if (DGV[columnIndex, row].Value != null) &&
(DGV[regionColumn, row].Value.ToString() == region)
sum += Convert.ToDecimal(DGV[1, row].Value);
return sum;
}
If I got it right, whenever you change the value in sales analyze combo, the tab page containing data grid should should be activate.
You can set the selected index of the tab control to the the data grid tab, and it should work
this.tabControl1.SelectedIndex = 1;//Index of data grid tab
I have a DatagridviewCombobox Column and am creating DatagridviewCombobox Cells on each row and adding items to it.
When I change the value of any (combobox) cell, it throws an exception saying that Datagridviewcombobox cell value is not valid.
and the cell value becomes '1'.
I am working on the datagridview_currentcelldirtystatechange event, but haven't been able to make it work.
The code below is creating rows and filling combobox cells with a sequence numbers.
int _rowLimit =1;
for (int i = _rowLimit - 1; i < _rowLimit; i++)
{
datagridview.Rows.Add();
item = i + 1;
datagridview[myColumn, i].Value = _rowLimit;
DataGridViewComboBoxCell oCell = datagridview.CurrentRow.Cells[myColumn] as DataGridViewComboBoxCell;
oCell.Items.Add(item);
((DataGridViewComboBoxColumn)datagridview.Columns[myColumn]).Items.IndexOf(_rowLimit);
((DataGridViewComboBoxColumn)datagridview.Columns[myColumn]).Items.Insert(index, item);
}
And below is what i am doing in datagridview_currentcelldirtystatechange event:
for (int innerIndex = 0; innerIndex < datagridview.Rows.Count; innerIndex++)
{
long sequence = 3;
long oldSequence = 2;
long tempValue= Convert.ToInt64(datagridview.Rows[innerIndex].Cells[myColumn].Value);
if (tempValue <= sequence && tempValue> oldSequence)
{
datagridview.Rows[innerIndex].Cells[myColumn].Value = tempValue+ 1; // increment the sequence
// value here i am getting is correct , but it doesn't show in the DatagridviewCombobox cell where it gets changed of gridview and the mentioned exception is thrown.
}
Any help would be appreciated.
Thanks.
the error on selectedindexChange value of the combobox cells and the exception of DataGridviewComboboxcell value is not valid .. that automatically did change the selected vlue to '1'..
i fixed this issue by adding the DatagridviewComboBoxColumn property in the designer file.
this.columnName.ValueType = typeof(long);
typeof(long) // this is what what i wanted to show the value in the datagridviewcombobox column.
Issue has now resolved.
Thanks.
I have a situation where I have Multiple GridViews on a page GridView1 - GridView4.
All these GridViews have TextBoxes in the cells, I would like to run a calculation function only on the Column of the TextBox that was Clicked and on that particular GridView.
Example: A user clicks on a TextBox in Column 2 of GridView3 and changes a number value, the OnTextChange event of that particular TextBox should fire to run a calculation and total all the numbers of GridView3 Col2 in a footer label.
I searched and all the other suggestions I found assume you have only 1 grid and that you know what preset Column the calculation is done at IE a prices column, But I don't know what Column info a user will edit in any of my 4 GridViews.
I gave up and resolved to just running the calculation code on the Entire GridView, not just the column edited, but to do this I need to Get the GridView.ID of the Gridview containing the TextBox. Extensive serches came up with how to get the ID of the sender Item but not the GridView.ID that contains the sender.
If anyone can help with either situation, please do so, I would really appreciate it.
As Per the conversations below, I have edited this post to include the Edited answer provided by Tim in the hopes that others may learn from this code:
//This is working code
protected void textBox_TextChanged(Object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
GridViewRow gvRow = (GridViewRow)txt.NamingContainer;
GridView Grid = (GridView)gvRow.NamingContainer;
// if you need the index of the column of the TextBox
int colIndex = 0;
for (int i = 0; i < gvRow.Cells.Count; i++)
{
if (gvRow.Cells[i] == txt.Parent)
{
colIndex = i;
Msg.Text = "Col: "+colIndex.ToString();
break;
}
}
int gridNum = 0;
switch (Grid.ID)
{
case "GridView1":
gridNum = 1;
break;
case "GridView2":
gridNum = 2;
break;
case "GridView3":
gridNum = 3;
break;
case "GridView4":
gridNum = 4;
break;
}
Label ColTotal = (Label)Grid.FooterRow.FindControl("G" + gridNum + "TotalPP" + colIndex);
double total = 0;
foreach (GridViewRow row in Grid.Rows)
{
TextBox tb = (TextBox)row.FindControl(txt.ID);
double d;
if (double.TryParse(tb.Text, out d))
total += d;
}
ColTotal.Text = total.ToString();
}
As you can see, according to the way the code is set up, the colIndex will help me find the footer label for each column and put it's total in.
You could let all TextBoxes handle the same TextChanged event and use this (untested) code:
protected void textBox_TextChanged(Object sender, EventArgs e)
{
TextBox txt = (TextBox) sender;
GridViewRow gvRow = (GridViewRow) txt.NamingContainer;
GridView gv = (GridView) gvRow.NamingContainer;
// if you need the index of the column of the TextBox
// as commented below you're using .NET 2.0
int colIndex;
for (int i = 0; i < gvRow.Cells.Count; i++)
{
if (gvRow.Cells[i] == txt.Parent)
{
colIndex = i;
break;
}
}
double total = 0;
foreach (GridViewRow row in gv.Rows)
{
TextBox tb = (TextBox)row.FindControl(txt.ID);
double d;
if (double.TryParse(tb.Text, out d))
total += d;
}
var tbFooter = (TextBox) gv.FooterRow.FindControl(txt.ID);
tbFooter.Text = total.ToString();
}
Of course assuming that all TextBoxes are in TemplateFields and the footer TextBox has the same ID. Remember to set AutoPostback to true if you want to postback immediately.
When TextChanged runs, sender is a reference to that textbox. You can use the parent property to find out what is the parent of that textbox. If you chain parents together (something like txt.Parent.Parent, you'll eventually find the GridViewRow, and GridView objects. Since you want to calculate the column, you'd have to find the cell that the control is in first, find the cell's index, then bubble up to the grid, loop through each row in that grid, and grab the values in the matching index. I hope you don't have paging enabled, because that will skew the numbers (since they aren't all present). Not an easy task, but possible.
From a performance perspective, you would get better performance with a client-side solution using JQuery or something else.
I need to use a the DataGridView control to display a large number of columns. I have a DataGridViewCell class that specifies a custom Paint method for each cell. I have added the columns like so...
int ColumnCount = 5000;
DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell();
for (int i = 0; i < ColumnCount; i++)
{
dataGridView1.Columns.Add(new DataGridViewColumn() { CellTemplate = cell, FillWeight = 1 });
}
The problem is, this takes ages to add all the columns, much longer than it should really take. When I add the columns I can see the size of the scroll bar at the bottom of the DataGridView getting smaller like the grid is drawing each column each time I add one.
Does anyone know of a quicker way to add a large number of columns, or how to prevent the DataGridView updating until all the columns have been added?
I've tried disabling resizing, SuspendLayout(), and setting dataGridView1.Visible = false.
If you use the VirtualMode = TRUE for the DataGridView, you can refresh ONLY the screen portion.