C# comboBox from dataGridView? - c#

I want combobox with values from one cell datagridview. i try this, but don't work :( any ideas?
comboBox1.Items.Clear();
foreach (DataGridViewRow row in dataGridView1.Rows)
{
comboBox1.Items.Add(row.Cells[2].Value.ToString());
}

The Value property is null, and throwing the exception when you call ToString() on it.
Check for null first:
if (row.Cells[2].Value != null)
comboBox1.Items.Add(row.Cells[2].Value.ToString());
Alternatively, use LINQ to iterate through the rows and populate the ComboBox:
comboBox1.Items.AddRange(
dataGridView1.Rows.Cast<DataGridViewRow>()
.Where(x => x.Cells[2].Value != null)
.Select(x => x.Cells[2].Value.ToString())
.ToArray());

I think row.Cells[2].Value has NULL. Try
row.Cells[1].Value

The row.Cells[i] collection always starts at 0, so depending on how many columns you have, row.Cells[2] is actually the third column, and could be non existent. However, if that's the case, you'd like end up with a 'System.IndexOutOfRange' exception instead.
It's more likely that the cell doesn't have anything in it, or that the row doesn't even exist. Step through the debugger and see where the error is coming up.
Another, more specific way of handling this would be to specify the range by using a for loop instead:
// Rows.Count specifies the range explicitly - if you have 5 rows,
// if i <= 5, it will loop through until it increments to 6, then stop.
for(int i = 0; i <= dataGridView1.Rows.Count; i++)
{
if (dataGridView1.Rows.Cells[2].Value != null)
comboBox1.Items.Add(dataGridView1.Rows.Cells[2].Value.ToString());
}

Related

Alternative to setting values in foreach C#

I'm rather new to MVC/C# and from what I understand, foreach is read-only.
I would like there to be a method that sets the values that are null to false if that method is called.
IQueryable<CurrentMatch> FindTheMatch = (from row in db.CurrentMatches
where row.UserId.ToString() == UserIdentity
where row.MatchID == MatchIdentity
select row);
List<CurrentMatch> SetRemainingValuesToFalse = FindTheMatch.ToList();
I know that the part below wont work, it just demonstrates how I'm trying to achieve what I want to do.
foreach (var Column in SetRemainingValuesToFalse)
{
if (Column == null)
{
Column = false;
}
}
As the row has a large number of properties it wouldn't be scaleable in the future to set each property manually.
You just need to use a standard for loop instead of a foreach. You can't modify the collection inside a foreach because that is how the iterator works. You can however modify values on the objects themselves.
See also: Changing objects value in foreach loop?
I think you have this sort of the wrong way round. If you set that value to false inside any sort of loop, the context is lost when you exit that iteration of the loop.
Instead, what you probably want to do is, when consuming the list, treat nulls as false. You can use the null coalesce operator for this (??)
foreach (var row in FindTheMatch)
{
DoSomethingInterestingWith(row.Column ?? false); // pass false if Column is null.
}
for(int i=0;i<SetRemainingValuesToFalse.length;i++)
{
if (SetRemainingValuesToFalse[i] == null)
{
SetRemainingValuesToFalse[i] = false;
}
}
you are slightly misunderstanding how the foreach is working
foreach(var c in col)
reads as
While col.asEnumerable.HasValues let c = col.asEnumerable.Current
because of this you can't change either the enumerable or its current value with out breaking the loop, however if the enumerable isn't attached to the collection you are changing then you have no problems
ToList for example will clone the collection meaning the enumerable is attached to the clone not the original collection
foreach(var c in col)
col.Remove(c);
will error
foreach(var c in col.ToList())
col.Remove(c);
works fine
like wise
foreach(var c in col)
if(c.Field == null) c.Field = false;
is also fine because you are editing the the content of the current enumerable location not the location itself
however your stated desire of just replacing nulls in a collection is much simpler
col.Select(c=>c??false); //c#6
col.Select(c=>c == null? false : c); //c#<6
as you seem to be working with something akin to a datatable then you could do this
foreach(var row in table.Rows)
foreach(var col in table.Columns)
row[col] = row[col] ?? false;

Clearing datagridview starting from the chosen row

I want to clear the datagridview starting from the row which user chose. I am trying a few ways to implement it, but they all generate some errors, now I have something like this:
foreach(DataGridViewRow row in this.dataGridView1.Rows)
{
if(row.Index >= odelementu - 1)
dataGridView1.Rows.RemoveAt(row.Index);
}
User need to choose from which row we should clear the datagridview and then click the button
odelementu //this variable represents the starting row
I don't know why the loop misses some rows. I would be grateful for any advices
It's because you modify the DataGridViewRowCollection in the foreach loop and make the index gotten becomes inexact. Try this instead:
while(dataGridView1.Rows.Count>=odelementu) {
dataGridView1.Rows.RemoveAt(odelementu-1);
}
public void RemoveRows()
{
var selectedrows = datagridview.SelectedRows.Cast<DataGridViewRow>();
if (selectedrows.Count() == 0)
return;
var fromIndex = selectedrows.Last().Index;
datagridview.Rows.Cast<DataGridViewRow>()
.Where(p=>p.Index > fromIndex)
.ToList()
.ForEach(p=>datagridview.Rows.Remove(p));
}

Ultrawingrid - Select row based on unique value

Is there a way to select a row in an ultrawingrid based on the value of one of its columns (ID column)? I have been trying to find out how to do this with little success.
I have a global variable that is the 'active ID' (i.e the ID that is currently being edited within the application - it is the ID that the system sees as being selected and active) - but sometimes the selected row of the grid and the 'selected ID' variable don't match. I need to make sure they are the same in order to prevent user confusion. I am hoping to call the following code inside a refresh() function...
Perhaps something like (kinda-pseudo-code-ish):
int index; // This could be any number
foreach (row r in grid)
{
if (row.cell["ID"].value = index)
grid.selectedindex = thisRow;
}
Am I thinking along the right lines? If so, what is the correct syntax? If not, how else should I do this?
Got it.
int index;
foreach (UltraGridRow row in grid.Rows)
{
if (Convert.ToInt32(row.Cells["ID"].Value) == index)
{
grid.ActiveRow = row;
break;
}
}
Works just how I needed it to - sorry for answering my own question ;)
Yes. You can use the FirstOrDefault function to find a row matching a criteria:
var row = ultraGrid1.Rows.FirstOrDefault(r => r.Cells["Id"].Value.ToString() == "1");
Now that you (potentially) have the row where the cell contains the value you'd like, you can activate it to select it:
if (row != null)
row.Activate();
If you are bound to a DataTable or a list that has the ability to find an item by key, you can use the GetRowWithListIndex method of the Rows collection to find the UltraGridRow.
For example the following will activate the row with a key of 5:
DataTable dt = this.ultraGrid1.DataSource as DataTable;
DataRow dr = dt.Rows.Find(5);
this.ultraGrid1.Rows.GetRowWithListIndex(dt.Rows.IndexOf(dr)).Activate();
If your list doesn't support finding an item by key, you could use linq to find the item in the list as well. There is an example of finding an item with link here.
If you have multiple bands you can use the following:
int index;
ultraGrid1.DisplayLayout.Bands.OfType<Infragistics.Win.UltraWinGrid.UltraGridBand>()
.SelectMany(s => s.GetRowEnumerator(Infragistics.Win.UltraWinGrid.GridRowType.DataRow)
.OfType<Infragistics.Win.UltraWinGrid.UltraGridRow>())
.Where(s => s.Cells.Exists("ID"))
.FirstOrDefault(s => (int)s.Cells["ID"].Value == index)?
.Activate();
Note: Null-conditional Operator (?) requires C# 6.0 or higher. Otherwise you have to check, if FirstOrDefault(...)!=null and activate it then.

Delete Multiple rows from datagridview

I've a datagridview in which values are inserted.The gridview is like this.
Item PRID
------ ------
Item1 1
Item2 2
Item3 2
I am trying to compare the PRID with a variable which holds the selected row PRID.
What I've done so far.
foreach (DataGridViewRow dgv_r in PurchaseOrder_dgv.Rows)
{
if (dgv_r.Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
PurchaseOrder_dgv.Rows.Remove(dgv_r);
}
}
But it deletes the bottom row not the second row.and gives the following error.What I want is if the value of CurrentSelected_PRID_ForPurchaseOrder is equal to 2 then it should delete both the rows.I've tried it using for loop also but it gives me Index out of range error.It is giving the following error.
Object Reference Not set to an instance of object
The are a couple of ways around this. One is to do the following
for (int i = dataGridView1.RowCount - 1; i >= 0; i--)
if (String.Compare(dataGridView1.Rows[i].Cells[1].Value.ToString(), "2") == 0)
dataGridView1.Rows.Remove(dataGridView1.Rows[i]);
This is looping from the bottom end of the DataGridView and avoids the problem with removing rows whilst iterating.
I hope this helps.
As mellamokb pointed out the reason is because your editing the collection during the foreach. One solution would be to store the rows with the same PRID in a list first and then remove them after. Something like this
var rowsToRemove = new List<int>();
foreach (DataGridViewRow dgv_r in PurchaseOrder_dgv.Rows)
{
if (dgv_r.Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
rowsToRemove.Add(dgv_r.Index);
}
}
rowsToRemove.Reverse();
rowsToRemove.ForEach(i => PurchaseOrder_dgv.Rows.RemoveAt(i));
Another solution is to use a while loop instead which takes into account the possiblity of the collection size changing.
int i = 0;
while (i < PurchaseOrder_dgv.Rows.Count)
{
if (PurchaseOrder_dgv.Rows[i].Cells[1].Value.ToString() == CurrentSelected_PRID_ForPurchaseOrder.ToString())
{
PurchaseOrder_dgv.Rows.RemoveAt(i);
}
i++;
}

compare value property

how can I compare value property of item to datatable column called Value? Please help me with the syntax
if ((String)item.Value.IndexOf((string)results("value") Stringcomparison.CurrentCultureIgnoreCase) > -1)
{
returnItems.Add(item);
}
Your question and comment seem to be asking different things, but in both cases the answer is probably to unpick the big long line of code into explanatory variables:
string valueFromTable = currentRow["Value"].ToString();
bool itemValueContainsValueFromTable = item.Value.IndexOf(valueFromTable, StringComparison.CurrentCultureIgnoreCase) >= 0;
bool itemValueEqualsValueFromTable = item.Value.Equals(valueFromTable, StringComparison.CurrrentCultureIgnoreCase);
if (/* whichever of these you are interested in */)
{
returnItems.Add(item);
}
(ignoring error cases here, specifically if item.Value is null)
Note that to get a value from the DataTable you will need to pick a row. If you want to see if the item matches any row, then iterate over the rows (foreach (var row in table.Rows)).

Categories