how to sum values between columns in grid view with IFCondition? - c#

i have 3 columns in gridview, Column_A, Column_B and Column_total. then i do simple calculation between Column_A and Column_B and put it in Column_total.. example: when i enter value 1 in row Column_A and 1 in row Column_B, Column_total displays result 2. this simple code works:
private void Gdv_CellEndEdit(object sender, GridViewCellEventArgs e)
{
foreach (GridViewDataRowInfo Val in Gdv.SelectedRows)
{
Val.Cells["Column_Total"].Value = Convert.ToInt32(Val.Cells["Column_A"].Value) + Convert.ToInt32(Val.Cells["Column_B"].Value);
}
}
but in Column_total still showing result when I delete value in Column_A..
What I want, Column_total shows result when I enter value in Column_A, then when I delete value in Column_A then Column_total will return empty and won't show any result.. anyone can help?

Your method is not being recalled to reassign the updated value, I can only guess your .value is a string as you are using convert and didn't specify.
private void Gdv_CellEndEdit(object sender, GridViewCellEventArgs e)
{
bool _; /*Throw away value true/false output not needed,
prevents compiler warning.*/
foreach (GridViewDataRowInfo Val in Gdv.SelectedRows)
{
_ = int.TryParse(Val.Cells["Column_A"].Value, out a);
_ = int.TryParse(Val.Cells["Column_B"].Value, out b);
Val.Cells["Column_Total"].Value = (a != 0 || b != 0) ? (a + b) : "";
//If a or b is not 0, as int cannot be null; will sum(a+b), else return "" empty.
//Can change the or || to && if you require both to have values > 0.
}
}

finally.. agree with #JohnG, to solve my question problem is to use column expression.this is the last code snippet of my project :
// Create second column.
DataColumn Col_A = new DataColumn();
Col_A .DataType = System.Type.GetType("System.Decimal");
Col_A .ColumnName = "Column_A";
// Create second column.
DataColumn Col_Total = new DataColumn();
Col_Total .DataType = System.Type.GetType("System.Decimal");
Col_Total .ColumnName = "Column_total";
Col_Total .Expression = "Column_A * Column_B";
// Add columns to DataTable.
dt.Columns.Add(Col_A);
dt.Columns.Add(Col_Total);
DataView view = new DataView(dt);
dgv.DataSource = view;
I added 2 new columns named "Col_A" and "Col_Total" and in the summation column, the column "Column_B" is obtained from the gridview which displays the data source from mysql.
it really works, and I don't know if there's anything better than this?
Thank you for those of you who have answered my previous question.

Related

zero values instead of negative values in data grid view

I want to get rid of having negative values on the datagrid and I only want to show that once the item goes out of stock it will only show zero instead of -4
things to consider:
- I call my datagridview manually here:
void GetInventory()
{
using (SqlConnection con = new SqlConnection(Helper.GetConnection()))
{
con.Open();
string query = #"SELECT * FROM InventoryTable";
using (SqlCommand cmd = new SqlCommand(query, con))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
sda.Fill(dt);
dgvItem.DataSource = dt;
}
}
}
}
This shouldn't be handled in the sql query.
This is responsibility of the view logic. DataGridView is view's control and could be right place to convert quantity into "friendly" value.
DataGridView.CelLFormatting event handler could be right tool for the job.
// In constructor
dgvItem.CellFormatting += dgvItem_CellFormatting;
private void dgvItem_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
var dgv = sender as DataGridView;
if (dgv.Columns[e.ColumnIndex].Name != "Quantity")
{
return;
}
if (e.Value == null)
{
return;
}
var quantity = (decimal)e.Value;
if (quantity < 0)
{
e.Value = 0;
}
}
So you are having products that have minus stock but you do not want final user too see it but just to see 0 (which means out of stock).
There are many approach to this problem but let's say you cannot avoid getting into minus then you can filter your datagridview after populating it. Additional function = slower program so reconsider solving problem with not getting into minus.
So how it could be done is with extension.
You create it like this (i will put simple example):
public static void ReplaceAllNegativeWithZeros(this DataGridView dgv)
{
foreach(DataGridViewRow row in dgv.Rows)
{
foreach(DataGridViewCell cell in dgv.Cells)
{
//This will loop through all cells in your currently displayed datagridview
//You call this function like yourDataGridViewInForm.ReplaceAllNegativeWithZeros();
//Here check if value from cell meets your condition and then change it.
}
}
}
With this you can check all your cells (or just one column) and do with it's values whatever you need (replace them to 0 if < 0)
One way to do this is to have your query return a formatted or calculated value, like this for example
select case when i.quantity < 0 then 0 else i.quantity end as quantityZero,
i.*
from InventoryTable i
Now you can put the original quantity column invisible on your datagridview.
This way you have both the original value at hand should you need it, and a value that will show zero when < 0 to display
It is also best practice to not do select * but to always list the fields you need.
public static void ReplaceAllNegativeWithZeros(DataGridView dgv)
{
foreach (DataGridViewRow row in dgv.Rows)
{
foreach (DataGridViewCell cell in row.Cells)
{
if (cell.Value != null)
{
if (Convert.ToInt32(cell.Value.ToString()) < 0)
{
cell.Value = 0;
}
}
}
}
}

Looping through gridview and change certain column font colour

So I have a gridview and I wanted to make certain columns text a different colour... i.e every column that says actual I want this text to be green... can anybody help? My gridlooks similar to this.
Hour - actual A - target A - actual aa - target aa - actual b - target b.
And finally is there a way to reset the data in my gridview after a certain amount of time... i.e shiftstart 6am-2pm 2pm-10pm 10pm-6am... So the data refreshes after 8 hours back to zero.
public void Refreshdata(int selectedProduct, DateTime shiftStart, DateTime shiftEnd)
{
BizManager biz = new BizManager();
GridView1.DataSource = biz.GetPacktstatisticsForShift(
shiftStart
, shiftEnd
, selectedProduct).DefaultView;
GridView1.DataBind();
public DataTable CreatePackingStats(DataSet dset)
{
using (DataManager dmgr = new DataManager())
{
DataTable target = dset.Tables[0];
DataTable actual = dset.Tables[1];
DataColumn[] cols = new DataColumn[1];
cols[0] = actual.Columns["Hour"];
actual.PrimaryKey = cols;
DataTable final = new DataTable();
// Create table columns
foreach (DataColumn col in target.Columns)
{
final.Columns.Add(new DataColumn(col.ColumnName, col.DataType));
if (col.ColumnName.Contains("Target"))
{
// Add an equivilant actual column
string newColumnName = col.ColumnName.Replace("Target", "Actual");
final.Columns.Add(newColumnName, col.DataType);
}
}
//// Add rows to new table
foreach (DataRow row in target.Rows)
{
string key = row["Hour"].ToString();
DataRow newRow = final.Rows.Add();
// Store column value
foreach (DataColumn col in final.Columns)
{
if (col.ColumnName.Contains("HOUR") || col.ColumnName.Contains("Target"))
{
newRow[col.ColumnName] = row[col.ColumnName];
}
else
{
// Find actual data
DataColumn actColumn = actual.Columns[col.ColumnName] as DataColumn;
if (actColumn == null)
{
newRow[col.ColumnName] = 0;
}
else
{
if (string.IsNullOrEmpty(actual.Rows.Find(key)[col.ColumnName].ToString()))
{
newRow[col.ColumnName] = 0;
}
else
{
newRow[col.ColumnName] = actual.Rows.Find(key)[col.ColumnName].ToString();
}
}
}
}
}
return final;
The CreatePackingStats is populating my grid with added columns FYI.
I guess there is a way to add colour text whilst the code is looping through the data and creating extra columns, not sure how to do this tho.?
And also the CreatePackingStats is located in a class and not in the page behind aspx.
Sorry about all the questions I am new and learning, all your help will help to develop and I appreciate all the help I receive.
Right-click on your GridView then go to the properties tab and select events.In there you will find the event called RowDataBound.
In that event write your code to change the forecolor like:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
//here the Cells is an array where you can pass the index value of the cell where you want to check and if you don't know where the value is then you can do a for loop and then check the value
if (e.Row.Cells[0].Text == "someValue")
{
e.Row.Cells[0].ForeColor = System.Drawing.Color.Red;
}
}
}
Update 1 for comparing the value using the IndexOf()
As for the data what you have given, you have to change the compare function from == to IndexOf("SomeValue").For that, you can try the IndexOf("actual"). If it gives value > -1 then change the color.
or you can try the below code where I am looping through all the columns in the row(you can try to avoid the looping if you have knowledge on which column the value will occur):
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 0; i < e.Row.Cells.Count; i++)
{
if (e.Row.Cells[i].Text.ToLower().IndexOf("actual") > -1)
{
e.Row.Cells[i].ForeColor = System.Drawing.Color.Red;
}
}
}
}
Update 2 Adding the snapshots of sample data and it's output.
Here is the sample data with which I am working:
And here is the processed output using the IndexOf() loop over the in RowDataBound event.
Hope this helps.

Sum data for spesific row with filter from other row

I have grid with data being input.
Item Price Type
A 1000 1
B 1000 2
C 2000 2
D 3000 3
I want sum(price) with type that has value "2".
try
{
foreach (int i in gridView1.GetSelectedRows())
{
DataRow newRow = gridView1.GetDataRow(i);
if (newRow["NOMINAL"] is DBNull) { newRow["NOMINAL"] = 0; }
if (e.Column.FieldName == "IDISJ")
{
if (verifikasiNamaISJ(IDisj, e.RowHandle) == true)
{
TampilkanPesan.Error("Nama Item Sudah Ada!");
newRow["IDISJ"] = 0;
return;
}
newRow["IDISJ"] = IDisj;
gridView1.FocusedColumn = colNominal;
gridView1.FocusedRowHandle = e.RowHandle;
this.BeginInvoke((MethodInvoker)delegate
{
gridView1.ShowEditor();
});
cariDataItem(Convert.ToInt64(Global.PeriksaDBNullAngka(newRow["IDISJ"])));
newRow["NAMAISJ"] = NamaISJ;
newRow["NAMAJENISISJ"] = Jenis;
newRow["NOMINAL"] = 0;
}
DataTable dt = new DataTable()
>>>> txtTotalPotongan.EditValue = Convert.ToString(dt.Compute("SUM(NOMINAL)", "NAMAJENISISJ = 'Pemotongan'"));
>>>> txtTotalDiterima.EditValue = Convert.ToString(dt.Compute("SUM(NOMINAL)", "NAMAJENISISJ = 'Pendapatan'"));
}
}
catch (FbException ex)
{
TampilkanPesan.Error(ex.Message.ToString());
}
the line with >>>> was my work, but I have no idea how to do it. I guess I'm doing it wrong, since I put Datatable there. It's not data yet, still value of row.
But I don't know how to sum with filter, if not using filter I can do it. Please help me the right line of code for it.
I put this on gridview1_cellvaluechanged for every time something changes, it will update the value on textbox as well.
You could convert your datable to a list using System.Data.DataSetExtensions; and use Linq to filter and find the sum you are looking for.
var sum = dt.AsEnumerable().Where(x=> (int)x["Type"] == 2).Sum(x => (int)x["Price"]);
Here you can find a working example using your Items table.

How to set column ticked from other column

How can I set a value into gridview column? The thing is the column was added manually, not from the database. What I want is when the checklist value was 1 the cek22 column got ticked and when value was 0 the cek22 column was unticked. I used devexpress.
Example of my code that I used:
public void abc()
{
//select query in here
gridControl1.DataSource = dt;
//iam adding a column here
dt.Columns.Add("cek22",typeof(bool));
}
If your column is added manually then your column is working in unbound mode. So, you can just use its unbound expression. If you want to update your checklist column from cel22 then you can use CellValueChanging event.
Here is example:
var table = new DataTable();
table.Columns.AddRange(new[]
{
new DataColumn("preferred", typeof(string)),
new DataColumn("checklist", typeof(int))
});
table.Rows.Add("Director Fury", 1);
table.Rows.Add("Maria Hill", 0);
gridControl1.DataSource = table;
gridView1.PopulateColumns();
var column = new GridColumn();
column.FieldName = "cek22";
column.UnboundType = UnboundColumnType.Boolean;
column.UnboundExpression = "[checklist]";
column.Visible = true;
gridView1.Columns.Add(column);
gridView1.CellValueChanging += (sender, e) =>
{
if (e.Column.FieldName == "cek22")
gridView1.SetRowCellValue(e.RowHandle, "checklist", e.Value);
};
Here is the result:
The DevExpress Grid works with DataSource. So manipulate your DataSource and populate this to your Grid. The GridView will show this data. So if you want a check field i would recommend you to extend your DataSource with a bool Property. I don't now which DataSource you are using but if there is any bool value devexpress automatically add a checkbox column for you. If you want to link your custom column to the bool value in your DataSource you need to set the FieldName Property of the Column to your PropertyName.
If your checklist Property is 0 your bool Property return false and vice versa. This would be the easiest solution i guess. Assumed your are using a IList as DataSource.
Small example:
public class MyDataSource()
{
public int Checklist { get; set; }
public bool Cek22
{
get { return Checklist == 1; }
}
}
private void ExplainADevExpressGrid()
{
List<MyDataSource> dataSource = new List<MyDataSource>();
dataSource.Add(new MyDataSource());
myGrid.DataSource = dataSource;
}
Alternatively, add the column as part of the data source and populate it conditionally.
private void Form1_Load(object sender, EventArgs e)
{
DataTable dataTable = GetDataTable(10);
gridControl1.DataSource = dataTable;
}
private DataTable GetDataTable(int rows = 1)
{
DataTable table = new DataTable("Table1");
table.Columns.Add("checklist", typeof(int));
table.Columns.Add("cek22", typeof(bool));
for (int i = 0; i < rows; i++)
{
DataRow row = table.NewRow();
row["checklist"] = i % 2 == 0 ? 0 : 1;
row["cek22"] = ((int)row["checklist"]) == 0 ? false : true;
table.Rows.Add(row);
}
return table;
}

Update A Single cell within a row in datatable which contains multiple rows

How would i go about updating a single cell in a row so for example Row[0] i want to update the column "Value" with its current value +1. This is code i have which selects the single row but the Value updates with all the column "Value" data then +1
public void MetricChange()
{
DataTable dt = ds.Tables["MetricTable"];
int value = dt.AsEnumerable().Sum(r1 => r1.Field<int>("Value"));
if (Access.Checked)
{
ds.Tables["MetricTable"].Rows[0]["Value"] = value +1;
//ds.Tables["MetricTable"].Rows[1]["Value"] = value - 1;
Chart2.DataSource = ds.Tables["MetricTable"];
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
How would i just update the "Value" column within a single row???
Currently you are modifying only a single row, you need to do that for each row in the data table.
for(int i = 0; i < ds.Tables["MetricTable"].Rows.Count;i++)
ds.Tables["MetricTable"].Rows[i]["Value"] = value +1;
Its always better to check the dataset against null and table existence. Something like.
if(ds != null && ds.Tables.Count > 0 && ds.Tables["MetricTable"] != null)
This is how you do it :P
int val = Convert.ToInt32(ds.Tables["MetricTable"].Rows[0]["Value"]) + 1;
Then Update the row by this ds.Tables["MetricTable"].Rows[0][1] = val

Categories