Passing DataGridViewRow as referance - c#

I want to pass DataGridviewRow as a ref where i am assigning some value to its cells but i am unable to do this
foreach(DataGridViewRow dgr in dgvMarksEntryByClassWise.Rows)
{
RowValueSet(ref dgr);
}
Here it is giving Compile time Error because dgr is an foreach iteration variable
Also i tried to do it with for loop
for (int i = 0; i < dgvMarksEntryByClassWise.Rows.Count; i++)
{
RowValueSet(ref dgvMarksEntryByClassWise.Rows[i]);
}
But here also it is giving Compile time error:
A property,indexer or dynamic member acces cannot passed as an out reference
I referd this question asked on above errors but did't Found any appropriate solution of my problem
foreach iteration variable
A property,indexer or dynamic member acces cannot passed as an out reference
Please Suggest me how to Do this
Update Code
void RowValueSet(ref DataGridViewRow dgr)
{
dgr.Cells["StudentZero"].Value = ss.Where(w => w.MarksheetMarks == "0").Count();
if (ss.Count() != 0)
dgr.Cells["StudentISEmpty"].Value = Convert.ToInt16(lblTotlatStudent1.Text) - ss.Count();
else
dgr.Cells["StudentISEmpty"].Value = 0;
dgr.Cells["StudentEntry"].Value = ss.Count();
}

you cannot assign an iterated, enumerated item using a "foreach" or even a "for".
i got around that once, using that piece of code :
List<DataGridViewRow> lstDgr = new List<DataGridViewRow>();
foreach(DataGridViewRow dgr in dgvMarksEntryByClassWise.Rows)
{
DataGridViewRow dgrTemp = dgr;
RowValueSet(ref dgrTemp);
lstDgr.Add(dgrTemp);
}
dgvMarksEntryByClassWise.Rows.Clear();
dgvMarksEntryByClassWise.Rows.AddRange(lstDgr); //Not sure about the AddRange, try the Add method instead
Hope this helps

As stated in the comments above, you do not need to pass DataGridViewRow by reference. Remove ref from the parameter.
void RowValueSet(DataGridViewRow dgr)
{
dgr.Cells["StudentZero"].Value = ss.Where(w => w.MarksheetMarks == "0").Count();
if (ss.Count() != 0)
dgr.Cells["StudentISEmpty"].Value = Convert.ToInt16(lblTotlatStudent1.Text) - ss.Count();
else
dgr.Cells["StudentISEmpty"].Value = 0;
dgr.Cells["StudentEntry"].Value = ss.Count();
}
If the values in the grid do not appear to be updating, it's for another reason. Do you re-bind the grid when you need to refresh the display?

How about this ?
for (int i = 0; i < dgvMarksEntryByClassWise.Rows.Count; i++)
{
var myRow = dgvMarksEntryByClassWise.Rows[i];
RowValueSet(ref myRow);
}

I agree with the comments about not passing the row using ref. It is a reference type. You generally only use that keyword with value types (such as int, etc).
I've had problems with the DataGridView not updating after changing cell values and often have needed to call dataGridView1.Invalidate(); It depends how things are hooked up. If you use data-binding with a class that inherits from INotifyPropertyChanged then it always seems to work, but if you just change cell values I have noticed the odd time that it would not update.
Here is an example that works. Create a new app, add an empty DataGridView onto the form and replace the code with the following. This proves that you do not need to use ref.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Column1" });
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Column2" });
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Column3" });
dataGridView1.Columns.Add(new DataGridViewTextBoxColumn() { Name = "Column4" });
for (int i = 0; i <= 4; i++)
{
dataGridView1.Rows.Add();
}
foreach (DataGridViewRow row in dataGridView1.Rows)
{
RowValueSet(row);
}
}
private void RowValueSet(DataGridViewRow row)
{
row.Cells["Column1"].Value = "1";
row.Cells["Column2"].Value = "2";
row.Cells["Column3"].Value = "3";
row.Cells["Column4"].Value = "4";
}
}
I imagine that your problem lies elsewhere

Related

Loop based on null value of DataGridView cell

I'm still new to using c#. I searched many threads in the forum but couldn't find a solution. I would be grateful if you help.
The problem I can't solve;
If dataGridView2.Rows[i].Cells[5] value=null or empty then run the code below.
If it's full, I want it to increment [i] and move to the next line.
Loop stop point = column length of DataGridView
for (int i = 0; i < **???**; i++)
{
if (**???**)
{
TxtSayKod.Text = dataGridView2.Rows[i].Cells[2].Value.ToString() + dataGridView2.Rows[i].Cells[10].Value.ToString();
TxtHome.Text = dataGridView2.Rows[i].Cells[3].Value.ToString();
TxtAway.Text = dataGridView2.Rows[i].Cells[10].Value.ToString();
button1.PerformClick();
Thread.Sleep(3000);
btnupdate.PerformClick();
}
...
}
You can simplify looping by using a foreach-loop
foreach (DataGridViewRow row in dataGridView2.Rows)
{
if (row.Cells[5].Value is null) // Remove this: ;
{
string away = row.Cells[10].Value.ToString();
TxtSayKod.Text = row.Cells[2].Value.ToString() + away;
TxtHome.Text = row.Cells[3].Value.ToString();
TxtAway.Text = away;
button1.PerformClick();
Thread.Sleep(3000);
btnupdate.PerformClick();
}
}
Even when using a for-statement, you could assign the current row to a variable to simplify the following code:
for (int i = 0; i < dataGridView2.Rows.Count; i++)
{
var row = dataGridView2.Rows[i];
if (row.Cells[5].Value is null)
{
string away = row.Cells[10].Value.ToString();
...
}
}
Note that test is int only works if the value has been assigned to the cell as int and not say as number.ToString(). Otherwise, if it was as string, test:
if (row.Cells[3].Value is null or string { Length: 0 })
This uses a type pattern followed by a property pattern. See: Pattern Matching in C# 8.0
The semicolon (;) after your if (**???**) ; (in the unedited question) terminates the if-statement. Remove it to have to following code block to be executed as part of the if.
Do like this, run a loop for all rows and check the respective cell.
foreach (DataGridViewRow row in dataGridView2.Rows)
{
if (row.Cells[5].Value is not null && row.Cells[5].Value.ToString() == string.Empty)
{
}
}

Can't select row or control the scroll bar with DataGridVew

Maybe this's a newbie question.But I've been searching high and low with no luck as whatever I tried didn't work.
I have a DataGridView named dgvDeviceList which contains 5 columns:ID,Device Name,Mac Address,RSSI and Advertisement Type in the FormMain window.
When I use a method to scan the Bluetooth device nearby,and once find one,the DataGridView will add a new created row.
But I can't select row or control(scroll up/ down) the scroll bar when scanning is in process or stopped.And it looks that the dgvDeviceList doesn't have scroll bar.On some forums,it's described as a multiple threading problem,but unfortunately the method they provided can't work it out. Here's the code:
int rowIndex = 1;
private void SetupScanResultHandler()
{
ScanCallBack.ScanResultHandler = (result) =>
{
if (result != null)
{
foreach (var item in result.ScanRecords)
{
//the following InvokeRequired method is provided by internet
if (dgvDeviceList.InvokeRequired)
{
dgvDeviceList.Invoke((MethodInvoker)(() =>
{
SetupDeviceListDataGridView(item);
}));
}
else
{
SetupDeviceListDataGridView(item);
}
rowIndex++;
}
}
};
}
private void SetupDeviceListDataGridView(CyScanRecord item)
{
DataGridViewRow row = dgvDeviceList.Rows[dgvDeviceList.Rows.Add()];
row.Cells[0].Value = rowIndex;
row.Cells[1].Value = Utility.GetDeviceName(item.AdvertisementData.RawData.Length, item.AdvertisementData.RawData);
row.Cells[2].Value = Utility.InsertFormat(item.PeerDeviceAddress.Address.ToString("X12"), 2, ":");
row.Cells[3].Value = item.RSSI.ToString() + "dBm";
row.Cells[4].Value = item.AdvertisementType.ToString();
}
I will be really grateful if you could post some code or direct me to
the right method that I should look into. Thanks.
Add values to DataTable instead of the DGV. Make sure you add new row : DataRow newRow = new dt1.Rows.Add();
private void SetupDeviceListDataGridView(DataRow row)
{
row[0] = 5;
row[1] = 25;
row[2] = 25;
row[3] = 10;
row[4] = 35;
dgvDeviceList.DataSource = null;
dgvDeviceList.DataSource = dataTabl;
}
Oops!!I set the Enableproperty to falsein the property list.The code dgvDeviceList.enable = true;can solve the issue.There should be no mistakes.
Listview and Datagridview are always disabled

how to make gridcolumn type boolean check base on parsing

In my firstform, the gridview shows this:
and then i want to parsing to secondform iam using this code
string asscode = gridView1.GetFocusedRowCellValue("AsstCode").ToString();
Assistant assist = new Assistant(asscode);
assist.show();
When parsing, the string is one variable, so i need to split them. I'm using this split to break them
string ass_code;
public Assistant(string z) //this is form 2
{
InitializeComponent();
ass_code = z;
}
in second form i already set a gridview.datasource from another query and so i need to add custom column to the gridview, iam using this code
private void button1_Click(object sender, EventArgs e)
{
string[] names = ass_code.Split(';');
gridView1.BeginUpdate();
DataColumn col = dt.Columns.Add("X", typeof(Boolean));
GridColumn column = gridView1.Columns.AddVisible(col.ColumnName);
column.Caption = col.Caption;
column.Name = col.ColumnName;
gridView1.EndUpdate();
}
for the secondform interface, the gridview display this
what i want to ask is
how do i make the column x got checked base on the asscode so 0110300 and 0110164 and the other value not checked. as you can see on column x it got gray colour which the value is not 1 or 0
when i try to
//string[] names = ass_code.Split(';');
//foreach (string xy in names)
//{
// MessageBox.Show(xy);
//}
it shows that the first was 0110159 but the second string 0110164 got space string on the first character. << because this use for list 1
UPDATE:
well iam using this code but its only check on 0110300 because it set 0110159 back to false
foreach (string x in names)
{
string[] names = ass_code.Split(';');
for (int i = 0; i < gridView1.RowCount; i++)
{
string xg = x.Trim();
string g = gridView1.GetDataRow(i)["code"].ToString().Trim();
if (g == xg)
{
gridView1.SetRowCellValue(i, "Dada", true);
}
else
{
gridView1.SetRowCellValue(i, "Dada", false);
}
}
}
UPDATE2
If leading / trailing spaces is cause of issue then you can do it in two ways:
first way:
string[] names = ass_code.Split(';');
// remove leading / trailing spaces
for (int i = names.Length-1; i >= 0; i-- )
names[i] = names[i].Trim();
second way:
string[] names = ass_code.Split(new char[] { ';', ' '}, StringSplitOptions.RemoveEmptyEntries);
You make to much handy stuff. The Devexpress Grid is really much simpler to use:
var data = //GETYOURDATA
gridControl.DataSource = data;
This populates your data to the grid. You even don't need to create any columns etc. If you want a value now, you shouldn't use GetRowCellValue(); Try to use your DataSource instead.
var actualRow = gridView.GetFocusedRow() as DataRowView;
MessageBox(actualRow["code"]); //Will print your code from code column
What you need to understand is that your DataSource is the source of trues and the GridView just show this data. This becomes more comfortable if you store your data in List<T>.
EXAMPLE:
public class Employee()
{
public int Code{get;set}
public string Name{get;set;}
public bool X {get{return Code == 0110300}}
public static List<Employee> ReadAll(){//Get your data};
}
public class MyForm() : XtraForm
{
var data = Employee.ReadAll();
gridControl.DataSource = data;
//Access Employee code
Employee emp = gridView.GetFocusedRow() as Employee;
MessageBox.Show(emp.Code.ToString());
}
UPDATE
Use the second approach from #Rupesh to remove your spaces. And uses Equals for string comparison. Further set your GridColumn 'X' to column.UnboundType = DevExpress.Data.UnboundColumnType.Bool; to make sure DevExpress don't override your data.
UPDATE-2
var names = ass_code.Split(';').Select(p => p.Trim()).ToList();
for (int i = 0; i < gridView1.RowCount; i++)
{
string g = gridView1.GetDataRow(i)["code"].ToString().Trim();
if (names.Contains(g))
gridView1.SetRowCellValue(i, "Dada", true);
else
gridView1.SetRowCellValue(i, "Dada", false);
}

Remove rows in datagridview

I have a method that stores each line in a gridview into the database, then if the save is successful, removes the row; but if it isn't successful (cannot be stored in the db) it does not remove the row. Unfortunately, I can't get the row-removal to work properly.
This is my current code:
public static void SavePAC(PlantAreaCode_CreateView CView)
{
List<int> removeRows = new List<int>();
// For each cell in the DataGrid, stores the information in a string.
for (rows = 0; rows < CView.dataGridView1.Rows.Count; rows++)
{
correctSave = false;
if (CView.dataGridView1.Rows[rows].Cells[col].Value != null)
{
// Creates a model, then populates each field from the cells in the table.
PModel = new PlantAreaCode_Model();
PModel.AreaCode = Convert.ToString(CView.dataGridView1.Rows[rows].Cells[0].Value);
PModel.AreaName = Convert.ToString(CView.dataGridView1.Rows[rows].Cells[1].Value);
PModel.Comments = Convert.ToString(CView.dataGridView1.Rows[rows].Cells[2].Value);
// Passes the model into the Database.
Database_Facade.Operation_Switch(OPWRITE);
}
if (correctSave == true) // correctSave is set in the database insert method.
{
removeRows.Add(rows);
}
}
foreach (int i in removeRows)
{
CView.dataGridView1.Rows.RemoveAt(0); // Deletes all bar the last row, including any rows that cause errors
}
}
I have also tried:
foreach (int i in removeRows)
{
CView.dataGridView1.Rows.RemoveAt(i);
}
But that crashes at halfway, because the Rows index keeps changing each time a row is removed.
How can I achieve this? How can I remove a row if the save is successful, but keep it if there is an error?
May this help:
1] Make sure correctSave is being modified correctly.
2] Revert the loop flow, Looping backward allow to remove the row processed by the loop without affecting the index of the next row to process.
for (rows = CView.dgvCreate.Rows.Count - 1; rows >= 0 ; rows--)
3] Use CView.dataGridView1.Rows.RemoveAt(rows);
Try to populate collection of rows for removing with DataGridViewRow not with index. This works for me.
public void SavePAC(PlantAreaCode_CreateView CView)
{
List<DataGridViewRow> removeRows = new List<DataGridViewRow>();
foreach (DataGridViewRow row in CView.dataGridView1.Rows)
{
correctSave = false;
if (row.Cells[col].Value != null)
{
// Creates a model, then populates each field from the cells in the table.
PModel = new PlantAreaCode_Model();
PModel.AreaCode = Convert.ToString(row.Cells[0].Value);
PModel.AreaName = Convert.ToString(row.Cells[1].Value);
PModel.Comments = Convert.ToString(row.Cells[2].Value);
// Passes the model into the Database.
Database_Facade.Operation_Switch(OPWRITE);
}
if (correctSave == true) // correctSave is set in the database insert method.
{
removeRows.Add(row);
}
}
foreach (DataGridViewRow rowToRemove in removeRows)
{
CView.dataGridView1.Rows.Remove(rowToRemove);
}
}
You have to sort removeRows in descending order.
List<int> removeRowsDesc = removeRows.OrderByDescending(i => i);
Then use the foreach loop
foreach (int i in removeRowsDesc)
{
CView.dataGridView1.Rows.RemoveAt(i);
}
This way the reindexing wont affect the deletion.

Dynamically creating variables in C#

I am trying to do something like this:
for (int i = 1; i < nCounter ; i++)
{
string dvName = "dv" + i.ToString();
System.Windows.Forms.DataGridView dvName = new DataGridView();
// other operations will go here..
}
As you can guess, what I am trying to do is at i == 1, create a DataGridView with name dv1, and at i == 2, create a DataGridView with name dv2, but I can't.
Visual studio squiggles saying "a local variable named dvName is already delared in this scope" I also tried the following:
for (int i = 1; i <nCounter ; i++)
{
System.Windows.Forms.DataGridView dv & i = new DataGridView();
// other operations will go here..
}
But VS squiggles again, I hope you understood what I am trying to accomplish. Can anyone suggest how can I do this?
What you really need is a Dictionary<int, DataGridView> grids. Populate it in your for loop (grids[i] = new DataGridView();) and then, later, use the required grid (grids[someCalculatedIndex])
Hope this helps.
try a data structure where you can hold your variables eg dict etc
System.Collections.Generic.Dictionary<string,System.Windows.Forms.DataGridView>
grids = new Dictionary<string,System.Windows.Forms.DataGridView>();
for (int i = 1; i <nCounter ; i++)
{
grids.Add("dv" + i.ToString(), new DataGridView());
}
// to work on grid 1
DataGridView grid1 = grids["dv1"];
// so on
So your are trying to create the variable name dynamically? That's not possible. Why not use an Array or a List (or even a Dictionary)? Or do you want to just set the name of the control?
var list = new List<DataGridView>();
for (int i = 1; i <nCounter ; i++)
{
System.Windows.Forms.DataGridView dvName = new DataGridView();
dvName.Name = "dv" + i.ToString();
list.Add(dvName);
// other operations will go here..
}
foreach (var dv in list)
{
...do something...
}
DataGridView secondDv = list.Single(dv=>dv.Name == "dv2");
secondDv.DoSomething()
Not clear want you want to do...

Categories

Resources