Alternative to setting values in foreach C# - 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;

Related

C# comboBox from dataGridView?

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());
}

Update specific object in array

I have a DataTable and an array of objects that I loop through.
For each row in a data table, I search through my collection of objects with Linq, and if found, that object needs to be updated.
But how do I refresh my collection without reloading it from the database?
Car[] mycars = Cars.RetrieveCars(); //This is my collection of objects
//Iterate through Cars and find a match
using (DataTable dt = data.ExecuteDataSet(#"SELECT * FROM aTable").Tables[0])
{
foreach (DataRow dr in dt.Rows) //Iterate through Data Table
{
var found = (from item in mycars
where item.colour == dr["colour"].ToString()
&& item.updated == false
select item).First();
if (found == null)
//Do something
else
{
found.updated = true;
Cars.SaveCar(found);
//HERE: Now here I would like to refresh my collection (mycars) so that the LINQ searches on updated data.
//Something like mycars[found].updated = true
//But obviously mycars can only accept int, and preferably I do not want to reload from the database for performance reasons.
}
How else can I search and update a single item in the array?
You don't need to update your collection - assuming Car is a class, you've already updated the object that the array refers to by setting found.updated to true.
Don't forget that the array only contains references - so the found reference is the same reference which is in the array; updating the object via either variable will result in the change being visible via the other one.

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.

Passing data out

I'm currently having a bit of a nightmare with a foreach loop. In a nutshell, what I am trying to do is split a string and then filter this data based on the string. I then need to bind the said data to a control of filter it further down the line. So far, I have the following code
if (Session["Contract"] != null)
{
string[] contract = Session["Contract"].ToString().Split(',');
foreach (string i in contract)
{
if (i.ToString() != "")
{
data = data.Where(x => x.Term.Trim().ToUpper().Contains(i.ToString().Trim().ToUpper()));
}
}
}
LV_Jobs.DataSource = data;
LV_Jobs.DataBind();
Now when looping through, the filtering works fine, but once you are finished with one item, the data variable is cleared? Obviously I need to pass "data" back out of the foreach loop. Can anyone point me in the direction of how to do this???
You are resetting data every time the loop iterates. Try this (depending on what data is)
var filteredData = new List<string>();
if (Session["Contract"] != null)
{
filteredData = Session["Contract"].ToString().Split(',').Join(
data,
i => i.ToString().Trim().ToUpper(),
x => x.Term.Trim().ToUpper(),
(i, x) => x);
}
LV_Jobs.DataSource = filteredData;
LV_Jobs.DataBind();
Simply collect the needed data out in a list of results or any other data structure declared outside of the for/foreach scope.
Your data variable is not cleared. Instead, in the last iteration of the foreach where i.ToString() != "" your Where() condition is not true. So data becomes an empty list.
You can break out of the foreach when you found what you were looking for.

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